Files
pdf/engine/include/pdfengine/pdf_document.hpp
T
2026-08-10 14:21:54 +05:30

308 lines
9.0 KiB
C++

#pragma once
#include <memory>
#include <string>
#include <vector>
#include <cstdint>
#include <array>
#if __has_include(<expected>)
#include <expected>
#elif __has_include(<tl/expected.hpp>)
#include <tl/expected.hpp>
namespace std {
using tl::expected;
using tl::unexpected;
}
#endif
namespace pdfengine {
enum class EngineError {
FileNotFound,
InvalidFormat,
PasswordRequired,
InvalidPassword,
PageOutOfBounds,
RenderFailed,
WriteFailed,
Unknown
};
struct DocumentMetadata {
std::string title;
std::string author;
std::string creator;
std::string producer;
std::string creationDate;
std::string modificationDate;
};
struct DocumentPermissions {
bool isEncrypted = false;
std::string encryption = "None";
int securityRevision = -1;
bool ownerUnlocked = false;
bool canPrint = true;
bool canPrintHighRes = true;
bool canModify = true;
bool canCopy = true;
bool canAnnotate = true;
bool canFillForms = true;
bool canExtractForAccessibility = true;
bool canAssemble = true;
};
struct PageImage {
int width;
int height;
std::vector<uint8_t> data;
};
struct Point2D {
double x;
double y;
};
struct DevicePoint {
int x;
int y;
};
struct InvalidatedRegion {
int pageIndex;
double x;
double y;
double width;
double height;
};
struct GlyphBounds {
std::string text;
double x;
double y;
double w;
double h;
double fontSize;
};
struct HitResult {
int glyphIndex = -1;
int caret = 0;
int line = -1;
};
struct TextSelection {
int startGlyph = 0;
int endGlyph = 0;
std::string text;
std::vector<GlyphBounds> rects;
};
struct FontInfo {
std::string fontName;
std::string type;
bool isEmbedded = false;
bool isSubset = false;
bool isVertical = false;
std::string encoding;
bool hasToUnicode = false;
std::string cmapName;
std::string cidSystemInfo;
std::string subsetTag;
std::string sourceType;
std::string substitutedFrom;
std::string substitutedTo;
std::string normalizedFamily;
std::string internalFontId;
uint32_t flags = 0;
double ascent = 0.0;
double descent = 0.0;
double capHeight = 0.0;
};
struct Glyph {
std::string text;
uint32_t unicode = 0;
std::string fontName;
uint32_t flags = 0;
double fontSize = 0.0;
double originX = 0.0;
double originY = 0.0;
double bboxX = 0.0, bboxY = 0.0, bboxW = 0.0, bboxH = 0.0;
double angle = 0.0;
int pageObjectIndex = -1;
int srcIndex = 0;
};
struct TextRun {
std::string text;
std::string fontName;
std::string fontFace;
int fontWeight = 400;
std::string fontStyle = "normal";
uint32_t flags = 0;
double fontSize = 0.0;
std::string internalFontId;
bool isEmbedded = false;
bool isEmbeddedFont = false;
bool isPredictedFont = false;
std::string type;
std::vector<Glyph> glyphs;
std::vector<int> objectIndices;
double x = 0.0, y = 0.0, w = 0.0, h = 0.0;
std::string fillColor = "#000000";
std::string paraId;
std::string fontFidelity = "exact";
};
struct TextLine {
std::vector<TextRun> runs;
std::vector<Glyph> glyphs;
double angle = 0.0;
double baselineY = 0.0;
double x = 0.0, y = 0.0, w = 0.0, h = 0.0;
};
struct Paragraph {
std::vector<TextLine> lines;
double x = 0.0, y = 0.0, w = 0.0, h = 0.0;
};
struct PageModel {
std::vector<Paragraph> paragraphs;
double width = 0.0;
double height = 0.0;
int pageIndex = 0;
};
class PdfPage {
public:
virtual ~PdfPage() = default;
[[nodiscard]] virtual double width() const noexcept = 0;
[[nodiscard]] virtual double height() const noexcept = 0;
[[nodiscard]] virtual std::expected<PageImage, EngineError> render(int dpi = 96) const = 0;
[[nodiscard]] virtual std::expected<PageImage, EngineError>
renderRegionRaw(int dpi, double yTopPt, double heightPt) const {
(void)dpi; (void)yTopPt; (void)heightPt;
return std::unexpected(EngineError::Unknown);
}
[[nodiscard]] virtual std::expected<PageImage, EngineError>
renderTile(int dpi, double xPt, double yPt, double wPt, double hPt) const {
(void)dpi; (void)xPt; (void)yPt; (void)wPt; (void)hPt;
return std::unexpected(EngineError::Unknown);
}
[[nodiscard]] virtual std::expected<std::string, EngineError> extractText() const = 0;
[[nodiscard]] virtual std::expected<std::vector<GlyphBounds>, EngineError> extractTextWithBounds() const = 0;
[[nodiscard]] std::expected<std::vector<GlyphBounds>, EngineError> orderedGlyphs() const;
[[nodiscard]] std::expected<HitResult, EngineError> hitGlyph(double x, double y) const;
[[nodiscard]] std::expected<TextSelection, EngineError>
selectRange(double ax, double ay, double bx, double by) const;
[[nodiscard]] virtual std::expected<PageModel, EngineError> extractDocumentModel() const = 0;
[[nodiscard]] virtual std::expected<std::vector<FontInfo>, EngineError> getFonts() const = 0;
[[nodiscard]] virtual std::expected<std::vector<std::string>, EngineError> extractAnnotationsText() const = 0;
struct AnnotationInfo {
std::string id;
std::string type;
double x = 0.0, y = 0.0, width = 0.0, height = 0.0;
std::string color;
std::string author;
std::string content;
std::string timestamp;
int pageIndex = 0;
double thickness = 0.0;
std::vector<std::vector<Point2D>> paths;
std::vector<std::array<Point2D, 4>> quadPoints;
std::string fieldName;
std::string fieldValue;
std::string fieldType;
int fieldFlags = 0;
std::vector<std::string> fieldOptions;
};
[[nodiscard]] virtual std::expected<std::vector<AnnotationInfo>, EngineError> extractAnnotations() const = 0;
[[nodiscard]] virtual std::expected<double, EngineError> getGlyphWidth(const std::string& fontName, uint32_t charcode, double fontSize) const = 0;
[[nodiscard]] virtual DevicePoint pageToDevice(const Point2D& pagePoint, int deviceWidth, int deviceHeight, int rotate = 0) const noexcept = 0;
[[nodiscard]] virtual Point2D deviceToPage(const DevicePoint& devicePoint, int deviceWidth, int deviceHeight, int rotate = 0) const noexcept = 0;
[[nodiscard]] virtual std::expected<std::string, EngineError> extractDisplayListJson() const = 0;
[[nodiscard]] virtual std::expected<std::vector<uint8_t>, EngineError> extractImageXObject(const std::string& name) const = 0;
};
namespace fonts::pdf_fonts { class Font; }
class PdfDocument {
public:
virtual ~PdfDocument() = default;
[[nodiscard]] static std::expected<std::shared_ptr<PdfDocument>, EngineError>
loadFromFile(const std::string& path, const std::string& password = "");
[[nodiscard]] static std::expected<std::shared_ptr<PdfDocument>, EngineError>
loadFromMemory(const std::vector<uint8_t>& data, const std::string& password = "");
[[nodiscard]] virtual int pageCount() const noexcept = 0;
[[nodiscard]] virtual DocumentMetadata metadata() const noexcept = 0;
[[nodiscard]] virtual DocumentPermissions permissions() const noexcept = 0;
struct OutlineItem {
std::string title;
int pageIndex = -1;
int level = 0;
};
[[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>
getFonts(int startPage = 0, int endPage = -1) const = 0;
[[nodiscard]] virtual std::expected<std::vector<uint8_t>, EngineError>
getFontData(const std::string& internalFontId) const = 0;
[[nodiscard]] virtual std::expected<std::vector<uint8_t>, EngineError>
getReconstructedFontData(const std::string& internalFontId) { (void)internalFontId; return std::unexpected(EngineError::Unknown); }
virtual void registerAuxFont(const std::string& internalFontId, const std::vector<uint8_t>& sfnt) { (void)internalFontId; (void)sfnt; }
[[nodiscard]] virtual std::expected<std::shared_ptr<fonts::pdf_fonts::Font>, std::string>
getResolvedFont(const FontInfo& fontInfo) = 0;
virtual std::expected<std::vector<InvalidatedRegion>, EngineError> applyEdits(const std::string& editsJson) = 0;
[[nodiscard]] virtual std::string validateLayout(int pageIndex, const std::string& jsonStr) { (void)pageIndex; (void)jsonStr; return "{}"; }
[[nodiscard]] virtual std::string lastReflowLayout() const { return {}; }
[[nodiscard]] virtual bool lastReflowOverflowed() const { return false; }
[[nodiscard]] virtual std::expected<std::vector<uint8_t>, EngineError>
saveIncremental() const = 0;
[[nodiscard]] virtual std::expected<std::vector<uint8_t>, EngineError>
saveFull() const = 0;
[[nodiscard]] virtual std::expected<std::vector<uint8_t>, EngineError>
saveFullForExport() const { return saveFull(); }
};
}