fix: reworked ui components
This commit is contained in:
@@ -182,7 +182,15 @@ public:
|
||||
[[nodiscard]] virtual int pageCount() const noexcept = 0;
|
||||
[[nodiscard]] virtual DocumentMetadata metadata() const noexcept = 0;
|
||||
|
||||
[[nodiscard]] virtual std::expected<std::shared_ptr<PdfPage>, EngineError>
|
||||
// A single entry in the document outline (bookmarks), flattened with a depth level.
|
||||
struct OutlineItem {
|
||||
std::string title;
|
||||
int pageIndex = -1; // -1 if the destination page can't be resolved
|
||||
int level = 0; // 0 = top-level
|
||||
};
|
||||
[[nodiscard]] virtual std::expected<std::vector<OutlineItem>, EngineError> extractOutline() const = 0;
|
||||
|
||||
[[nodiscard]] virtual std::expected<std::shared_ptr<PdfPage>, EngineError>
|
||||
getPage(int pageIndex) = 0;
|
||||
|
||||
[[nodiscard]] virtual std::expected<std::vector<FontInfo>, EngineError>
|
||||
|
||||
@@ -1530,6 +1530,52 @@ DocumentMetadata PdfiumDocument::metadata() const noexcept {
|
||||
return meta;
|
||||
}
|
||||
|
||||
#ifdef PDFENGINE_WITH_PDFIUM
|
||||
namespace {
|
||||
// Depth-first flatten of the bookmark tree into OutlineItems with a depth level.
|
||||
void walkOutline(FPDF_DOCUMENT doc, FPDF_BOOKMARK bm, int level,
|
||||
std::vector<PdfDocument::OutlineItem>& out) {
|
||||
while (bm && level <= 32 && out.size() < 5000) {
|
||||
PdfDocument::OutlineItem item;
|
||||
item.level = level;
|
||||
|
||||
unsigned long len = FPDFBookmark_GetTitle(bm, nullptr, 0);
|
||||
if (len > 2) {
|
||||
std::vector<unsigned short> buf(len / 2);
|
||||
FPDFBookmark_GetTitle(bm, buf.data(), len);
|
||||
item.title = utf16le_to_utf8(reinterpret_cast<const char16_t*>(buf.data()), buf.size());
|
||||
while (!item.title.empty() && item.title.back() == '\0') item.title.pop_back();
|
||||
}
|
||||
|
||||
FPDF_DEST dest = FPDFBookmark_GetDest(doc, bm);
|
||||
if (!dest) {
|
||||
FPDF_ACTION action = FPDFBookmark_GetAction(bm);
|
||||
if (action) dest = FPDFAction_GetDest(doc, action);
|
||||
}
|
||||
item.pageIndex = dest ? static_cast<int>(FPDFDest_GetDestPageIndex(doc, dest)) : -1;
|
||||
|
||||
out.push_back(std::move(item));
|
||||
|
||||
FPDF_BOOKMARK child = FPDFBookmark_GetFirstChild(doc, bm);
|
||||
if (child) walkOutline(doc, child, level + 1, out);
|
||||
bm = FPDFBookmark_GetNextSibling(doc, bm);
|
||||
}
|
||||
}
|
||||
} // namespace
|
||||
#endif
|
||||
|
||||
std::expected<std::vector<PdfDocument::OutlineItem>, EngineError> PdfiumDocument::extractOutline() const {
|
||||
#ifdef PDFENGINE_WITH_PDFIUM
|
||||
std::vector<PdfDocument::OutlineItem> result;
|
||||
if (doc_) {
|
||||
walkOutline(doc_, FPDFBookmark_GetFirstChild(doc_, nullptr), 0, result);
|
||||
}
|
||||
return result;
|
||||
#else
|
||||
return std::unexpected(EngineError::Unknown);
|
||||
#endif
|
||||
}
|
||||
|
||||
std::expected<std::shared_ptr<PdfPage>, EngineError> PdfiumDocument::getPage(int pageIndex) {
|
||||
#ifdef PDFENGINE_WITH_PDFIUM
|
||||
if (!doc_) {
|
||||
@@ -2156,6 +2202,54 @@ std::expected<void, EngineError> PdfiumDocument::applyEdits(const std::string& e
|
||||
spdlog::error("FPDF_MovePages failed from {} to {}", fromIndex, destPageIndex);
|
||||
return std::unexpected(EngineError::Unknown);
|
||||
}
|
||||
} else if (type == "delete_annotation") {
|
||||
if (!op.contains("data") || !op["data"].is_object()) {
|
||||
spdlog::error("delete_annotation operation missing 'data' object");
|
||||
return std::unexpected(EngineError::InvalidFormat);
|
||||
}
|
||||
std::string targetId = op["data"].value("annotationId", "");
|
||||
if (targetId.empty()) {
|
||||
spdlog::error("delete_annotation missing 'annotationId'");
|
||||
return std::unexpected(EngineError::InvalidFormat);
|
||||
}
|
||||
|
||||
FPDF_PAGE page = FPDF_LoadPage(doc_, pageIndex);
|
||||
if (!page) {
|
||||
spdlog::error("Failed to load page index {} for delete_annotation", pageIndex);
|
||||
return std::unexpected(EngineError::Unknown);
|
||||
}
|
||||
|
||||
int count = FPDFPage_GetAnnotCount(page);
|
||||
int foundIndex = -1;
|
||||
for (int i = 0; i < count; ++i) {
|
||||
FPDF_ANNOTATION annot = FPDFPage_GetAnnot(page, i);
|
||||
if (!annot) continue;
|
||||
|
||||
// Reconstruct the same id extractAnnotations() exposes (NM, else anno_<page>_<index>).
|
||||
std::string id;
|
||||
unsigned long len = FPDFAnnot_GetStringValue(annot, "NM", nullptr, 0);
|
||||
if (len > 2) {
|
||||
std::vector<uint8_t> buf(len);
|
||||
FPDFAnnot_GetStringValue(annot, "NM", reinterpret_cast<FPDF_WCHAR*>(buf.data()), len);
|
||||
id = utf16le_to_utf8(reinterpret_cast<const char16_t*>(buf.data()), len / sizeof(char16_t));
|
||||
while (!id.empty() && id.back() == '\0') id.pop_back();
|
||||
}
|
||||
if (id.empty()) {
|
||||
id = "anno_" + std::to_string(pageIndex) + "_" + std::to_string(i);
|
||||
}
|
||||
FPDFPage_CloseAnnot(annot);
|
||||
|
||||
if (id == targetId) { foundIndex = i; break; }
|
||||
}
|
||||
|
||||
if (foundIndex >= 0) {
|
||||
if (!FPDFPage_RemoveAnnot(page, foundIndex)) {
|
||||
spdlog::error("FPDFPage_RemoveAnnot failed for index {}", foundIndex);
|
||||
}
|
||||
} else {
|
||||
spdlog::warn("delete_annotation: annotation '{}' not found on page {}", targetId, pageIndex);
|
||||
}
|
||||
FPDF_ClosePage(page);
|
||||
} else {
|
||||
spdlog::warn("Unsupported edit operation type: {}", type);
|
||||
}
|
||||
|
||||
@@ -78,6 +78,7 @@ public:
|
||||
|
||||
int pageCount() const noexcept override;
|
||||
DocumentMetadata metadata() const noexcept override;
|
||||
std::expected<std::vector<OutlineItem>, EngineError> extractOutline() const override;
|
||||
|
||||
std::expected<std::shared_ptr<PdfPage>, EngineError> getPage(int pageIndex) override;
|
||||
std::expected<std::vector<FontInfo>, EngineError> getFonts(int startPage = 0, int endPage = -1) const override;
|
||||
|
||||
Reference in New Issue
Block a user