190 lines
9.1 KiB
C++
190 lines
9.1 KiB
C++
#pragma once
|
|
|
|
#include <pdfengine/pdf_document.hpp>
|
|
|
|
#ifdef PDFENGINE_WITH_PDFIUM
|
|
#include <fpdfview.h>
|
|
#include <fpdf_text.h>
|
|
#endif
|
|
|
|
#include <memory>
|
|
#include <string>
|
|
#include <vector>
|
|
#include <mutex>
|
|
#include <optional>
|
|
#include <unordered_map>
|
|
#include <nlohmann/json_fwd.hpp>
|
|
#include "fonts/pdf_fonts/embedded_font_reconstructor.hpp"
|
|
namespace pdfengine::fonts::loader { class FontResolver; }
|
|
namespace pdfengine::fonts { class FontFace; }
|
|
|
|
namespace pdfengine::parser {
|
|
|
|
class PdfiumDocument;
|
|
|
|
#ifdef PDFENGINE_WITH_PDFIUM
|
|
using NativeDocHandle = FPDF_DOCUMENT;
|
|
using NativePageHandle = FPDF_PAGE;
|
|
using NativeTextHandle = FPDF_TEXTPAGE;
|
|
#else
|
|
using NativeDocHandle = void*;
|
|
using NativePageHandle = void*;
|
|
using NativeTextHandle = void*;
|
|
#endif
|
|
|
|
class PdfiumPage : public PdfPage {
|
|
public:
|
|
PdfiumPage(NativeDocHandle docHandle, NativePageHandle pageHandle, int pageIndex,
|
|
std::shared_ptr<PdfiumDocument> owner = nullptr);
|
|
~PdfiumPage() override;
|
|
|
|
PdfiumPage(const PdfiumPage&) = delete;
|
|
PdfiumPage& operator=(const PdfiumPage&) = delete;
|
|
PdfiumPage(PdfiumPage&& other) noexcept;
|
|
PdfiumPage& operator=(PdfiumPage&& other) noexcept;
|
|
|
|
double width() const noexcept override;
|
|
double height() const noexcept override;
|
|
|
|
std::expected<PageImage, EngineError> render(int dpi = 96) const override;
|
|
std::expected<PageImage, EngineError> renderRegionRaw(int dpi, double yTopPt, double heightPt) const override;
|
|
std::expected<PageImage, EngineError> renderTile(int dpi, double xPt, double yPt, double wPt, double hPt) const override;
|
|
std::expected<std::string, EngineError> extractText() const override;
|
|
|
|
std::expected<std::vector<GlyphBounds>, EngineError> extractTextWithBounds() const override;
|
|
std::expected<PageModel, EngineError> extractDocumentModel() const override;
|
|
std::expected<std::vector<FontInfo>, EngineError> getFonts() const override;
|
|
std::expected<std::vector<std::string>, EngineError> extractAnnotationsText() const override;
|
|
std::expected<std::vector<PdfPage::AnnotationInfo>, EngineError> extractAnnotations() const override;
|
|
|
|
std::expected<double, EngineError> getGlyphWidth(const std::string& fontName, uint32_t charcode, double fontSize) const override;
|
|
|
|
std::expected<std::string, EngineError> extractDisplayListJson() const override;
|
|
std::expected<std::vector<uint8_t>, EngineError> extractImageXObject(const std::string& name) const override;
|
|
|
|
DevicePoint pageToDevice(const Point2D& pagePoint, int deviceWidth, int deviceHeight, int rotate = 0) const noexcept override;
|
|
Point2D deviceToPage(const DevicePoint& devicePoint, int deviceWidth, int deviceHeight, int rotate = 0) const noexcept override;
|
|
|
|
private:
|
|
NativeDocHandle doc_ = nullptr;
|
|
NativePageHandle page_ = nullptr;
|
|
mutable NativeTextHandle textPage_ = nullptr;
|
|
int pageIndex_ = 0;
|
|
mutable std::mutex textMutex_;
|
|
std::shared_ptr<PdfiumDocument> ownerDoc_;
|
|
#ifdef PDFENGINE_WITH_PDFIUM
|
|
mutable std::unordered_map<std::string, FPDF_FONT> fontHandleCache_;
|
|
#endif
|
|
|
|
void ensureTextPageLoaded() const;
|
|
};
|
|
|
|
class PdfiumDocument : public PdfDocument, public std::enable_shared_from_this<PdfiumDocument> {
|
|
public:
|
|
explicit PdfiumDocument(NativeDocHandle docHandle);
|
|
PdfiumDocument(NativeDocHandle docHandle, std::vector<uint8_t> memoryBuffer);
|
|
~PdfiumDocument() override;
|
|
|
|
PdfiumDocument(const PdfiumDocument&) = delete;
|
|
PdfiumDocument& operator=(const PdfiumDocument&) = delete;
|
|
PdfiumDocument(PdfiumDocument&& other) noexcept;
|
|
PdfiumDocument& operator=(PdfiumDocument&& other) noexcept;
|
|
|
|
int pageCount() const noexcept override;
|
|
DocumentMetadata metadata() const noexcept override;
|
|
DocumentPermissions permissions() 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;
|
|
std::expected<std::vector<uint8_t>, EngineError> getFontData(const std::string& internalFontId) const override;
|
|
std::expected<std::shared_ptr<fonts::pdf_fonts::Font>, std::string> getResolvedFont(const FontInfo& fontInfo) override;
|
|
|
|
void invalidateCaches();
|
|
|
|
std::expected<std::vector<InvalidatedRegion>, EngineError> applyEdits(const std::string& editsJson) override;
|
|
std::expected<std::vector<uint8_t>, EngineError> saveIncremental() const override;
|
|
std::expected<std::vector<uint8_t>, EngineError> saveFull() const override;
|
|
std::expected<std::vector<uint8_t>, EngineError> saveFullForExport() const override;
|
|
|
|
std::string lastReflowLayout() const { return lastReflowLayout_; }
|
|
bool lastReflowOverflowed() const { return lastReflowOverflowed_; }
|
|
|
|
const std::vector<uint8_t>& getMemoryBuffer() const { return memoryBuffer_; }
|
|
|
|
private:
|
|
mutable std::string lastReflowLayout_;
|
|
mutable bool lastReflowOverflowed_ = false;
|
|
NativeDocHandle doc_ = nullptr;
|
|
std::vector<uint8_t> memoryBuffer_;
|
|
|
|
mutable std::vector<FontInfo> cachedFonts_;
|
|
mutable bool hasCachedFonts_ = false;
|
|
mutable std::mutex fontsMutex_;
|
|
|
|
mutable std::unordered_map<std::string, std::vector<uint8_t>> fontDataCache_;
|
|
mutable int fontDataScannedPages_ = 0;
|
|
|
|
std::optional<std::vector<uint8_t>>
|
|
getFontDataFromObjects(int pageIndex, const std::vector<int>& objectIndices,
|
|
const std::string& internalFontId) const;
|
|
|
|
mutable std::unordered_map<int, std::weak_ptr<PdfPage>> pageCache_;
|
|
mutable std::mutex pageCacheMutex_;
|
|
|
|
std::unique_ptr<pdfengine::fonts::loader::FontResolver> fontResolver_;
|
|
std::unordered_map<std::string, std::shared_ptr<fonts::pdf_fonts::Font>> resolvedFontsCache_;
|
|
std::mutex resolvedFontsMutex_;
|
|
|
|
#ifdef PDFENGINE_WITH_PDFIUM
|
|
mutable std::unordered_map<std::string, FPDF_FONT> loadedFontsCache_;
|
|
mutable std::unordered_map<std::string, std::vector<uint8_t>> loadedFontDataBuffers_;
|
|
mutable std::unordered_map<std::string, std::shared_ptr<fonts::FontFace>> loadedMeasureFaces_;
|
|
mutable std::mutex loadedFontsMutex_;
|
|
|
|
struct EmissionFont {
|
|
FPDF_FONT font = nullptr;
|
|
std::shared_ptr<fonts::pdf_fonts::Font> resolved;
|
|
std::shared_ptr<fonts::FontFace> measureFace;
|
|
};
|
|
EmissionFont loadEmissionFont(int pageIndex, const std::string& internalFontId,
|
|
double fontSize, const std::vector<uint32_t>& codepoints,
|
|
const std::vector<int>& srcObjects = {},
|
|
FPDF_FONT reuseFont = nullptr);
|
|
|
|
mutable std::unordered_map<std::string, fonts::pdf_fonts::ReconstructedFont> reconstructedFonts_;
|
|
mutable std::mutex reconstructedFontsMutex_;
|
|
void registerAuxFont(const std::string& internalFontId, const std::vector<uint8_t>& sfnt) override;
|
|
std::expected<std::vector<uint8_t>, EngineError> getReconstructedFontData(const std::string& internalFontId) override;
|
|
const fonts::pdf_fonts::ReconstructedFont* lookupReconFont(const std::string& internalFontId);
|
|
#ifdef PDFENGINE_WITH_QPDF
|
|
const fonts::pdf_fonts::ReconstructedFont* getReconstructedEmbeddedFont(const std::string& internalFontId);
|
|
#endif
|
|
|
|
void rebalanceEditedPages(const std::vector<int>& editedPages);
|
|
|
|
std::expected<void, EngineError> applyOp_replaceText(const nlohmann::json& op, int pageIndex);
|
|
std::expected<void, EngineError> applyOp_reflow(const nlohmann::json& op, int pageIndex);
|
|
std::expected<void, EngineError> applyOp_textOverlay(const nlohmann::json& op, int pageIndex);
|
|
std::expected<void, EngineError> applyOp_stamp(const nlohmann::json& op, int pageIndex);
|
|
std::expected<void, EngineError> applyOp_decoration(const nlohmann::json& op, int pageIndex);
|
|
std::expected<void, EngineError> applyOp_redaction(const nlohmann::json& op, int pageIndex);
|
|
std::expected<void, EngineError> applyOp_updateField(const nlohmann::json& op, int pageIndex);
|
|
std::expected<void, EngineError> applyOp_imageOverlay(const nlohmann::json& op, int pageIndex);
|
|
std::expected<void, EngineError> applyOp_highlight(const nlohmann::json& op, int pageIndex);
|
|
std::expected<void, EngineError> applyOp_freeText(const nlohmann::json& op, int pageIndex);
|
|
std::expected<void, EngineError> applyOp_comment(const nlohmann::json& op, int pageIndex);
|
|
std::expected<void, EngineError> applyOp_freehand(const nlohmann::json& op, int pageIndex);
|
|
std::expected<void, EngineError> applyOp_pageRotation(const nlohmann::json& op, int pageIndex);
|
|
std::expected<void, EngineError> applyOp_pageDeletion(const nlohmann::json& op, int pageIndex);
|
|
std::expected<void, EngineError> applyOp_pageReorder(const nlohmann::json& op, int pageIndex);
|
|
std::expected<void, EngineError> applyOp_deleteAnnotation(const nlohmann::json& op, int pageIndex);
|
|
std::expected<void, EngineError> applyOp_updateAnnotation(const nlohmann::json& op, int pageIndex);
|
|
#endif
|
|
};
|
|
|
|
std::vector<unsigned short> utf8_to_utf16le(const std::string& utf8);
|
|
std::string utf16le_to_utf8(const char16_t* utf16, size_t length);
|
|
std::string code_point_to_utf8(unsigned int cp);
|
|
|
|
} |