feat: updated annotations

This commit is contained in:
Furqan-14
2026-06-10 15:22:34 +05:30
parent ef544263a5
commit 42993cb839
5 changed files with 209 additions and 17 deletions
+81 -13
View File
@@ -1219,20 +1219,24 @@ std::expected<std::vector<PdfPage::AnnotationInfo>, EngineError> PdfiumPage::ext
info.color = hex;
}
// Ink paths
// Ink geometry: read the /InkList strokes so the frontend can redraw
// them as an interactive overlay (Adobe-style, non-destructive).
// Points are converted from PDF (bottom-up) to top-left page-point space
// to match the frontend's coordinate convention (same as the rect above).
if (subtype == FPDF_ANNOT_INK) {
int objCount = FPDFAnnot_GetObjectCount(annot);
for (int j = 0; j < objCount; ++j) {
FPDF_PAGEOBJECT obj = FPDFAnnot_GetObject(annot, j);
if (obj && FPDFPageObj_GetType(obj) == FPDF_PAGEOBJ_PATH) {
[[maybe_unused]] int pathCount = FPDFPath_CountSegments(obj); // PDFium has FPDFPath_CountSegments ? Wait, let me check pdfium headers. Actually FPDFPath_GetPathSegmentCount doesn't exist, it is FPDFPath_CountSegments probably, or FPDFPath_CountSegments / FPDFPath_GetPathSegment.
// Wait, looking at PDFium fpdf_edit.h: `FPDFPath_CountSegments` doesn't exist, it's `FPDFPath_CountSegments`?
// Let me check if I can use FPDFPath_CountSegments
// It is usually int FPDFPath_CountSegments(FPDF_PAGEOBJECT path);
// FPDF_PATHSEGMENT FPDFPath_GetPathSegment(FPDF_PAGEOBJECT path, int index);
// FPDFPathSegment_GetPoint(FPDF_PATHSEGMENT segment, float* x, float* y);
// int FPDFPathSegment_GetType(FPDF_PATHSEGMENT segment);
const double pageH = height();
unsigned long strokeCount = FPDFAnnot_GetInkListCount(annot);
for (unsigned long s = 0; s < strokeCount; ++s) {
unsigned long ptCount = FPDFAnnot_GetInkListPath(annot, s, nullptr, 0);
if (ptCount == 0) continue;
std::vector<FS_POINTF> pts(ptCount);
FPDFAnnot_GetInkListPath(annot, s, pts.data(), ptCount);
std::vector<Point2D> stroke;
stroke.reserve(ptCount);
for (const auto& p : pts) {
stroke.push_back(Point2D{static_cast<double>(p.x), pageH - static_cast<double>(p.y)});
}
if (!stroke.empty()) info.paths.push_back(std::move(stroke));
}
}
@@ -1864,7 +1868,71 @@ std::expected<void, EngineError> PdfiumDocument::applyEdits(const std::string& e
FPDFPage_CloseAnnot(annot);
FPDF_ClosePage(page);
} else if (type == "freehand") {
spdlog::info("Parsed freehand edit operation (stub)");
if (!op.contains("data") || !op["data"].is_object()) {
spdlog::error("freehand operation missing 'data' object");
return std::unexpected(EngineError::InvalidFormat);
}
auto data = op["data"];
FPDF_PAGE page = FPDF_LoadPage(doc_, pageIndex);
if (!page) {
spdlog::error("Failed to load page index {} for freehand", pageIndex);
return std::unexpected(EngineError::Unknown);
}
FPDF_ANNOTATION annot = FPDFPage_CreateAnnot(page, FPDF_ANNOT_INK);
if (!annot) {
spdlog::error("Failed to create ink annotation");
FPDF_ClosePage(page);
return std::unexpected(EngineError::Unknown);
}
double pageHeight = FPDF_GetPageHeightF(page);
std::string colorStr = data.value("color", "#000000");
unsigned int r = 0, g = 0, b = 0;
parseHexColor(colorStr, r, g, b);
FPDFAnnot_SetColor(annot, FPDFANNOT_COLORTYPE_Color, r, g, b, 255);
float thickness = static_cast<float>(data.value("thickness", 2.0));
FPDFAnnot_SetBorder(annot, 0.0f, 0.0f, thickness);
// Accumulate bounding box in PDF (bottom-up) space.
float minX = 1e9f, minY = 1e9f, maxX = -1e9f, maxY = -1e9f;
bool anyPoints = false;
if (data.contains("paths") && data["paths"].is_array()) {
for (const auto& path : data["paths"]) {
if (!path.is_array() || path.size() < 2) continue;
std::vector<FS_POINTF> pts;
pts.reserve(path.size());
for (const auto& pt : path) {
float px = static_cast<float>(pt.value("x", 0.0));
// Frontend stores ink points top-down in page points; flip to PDF bottom-up.
float py = static_cast<float>(pageHeight - pt.value("y", 0.0));
pts.push_back(FS_POINTF{px, py});
anyPoints = true;
minX = (std::min)(minX, px); maxX = (std::max)(maxX, px);
minY = (std::min)(minY, py); maxY = (std::max)(maxY, py);
}
if (pts.size() >= 2) {
FPDFAnnot_AddInkStroke(annot, pts.data(), pts.size());
}
}
}
if (anyPoints) {
float pad = thickness + 1.0f;
FS_RECTF rect;
rect.left = minX - pad;
rect.bottom = minY - pad;
rect.right = maxX + pad;
rect.top = maxY + pad;
FPDFAnnot_SetRect(annot, &rect);
}
FPDFPage_CloseAnnot(annot);
FPDF_ClosePage(page);
} else if (type == "page_rotation") {
if (!op.contains("data") || !op["data"].is_object()) {
spdlog::error("page_rotation operation missing 'data' object");