feat: updated annotations
This commit is contained in:
@@ -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");
|
||||
|
||||
Reference in New Issue
Block a user