Merge branch 'dev' of https://gitea.maskantech.in/gitea_admin/pdf into saqib
This commit is contained in:
@@ -212,6 +212,7 @@ public:
|
||||
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;
|
||||
|
||||
|
||||
@@ -166,6 +166,7 @@ private:
|
||||
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);
|
||||
|
||||
@@ -44,7 +44,7 @@ std::expected<std::vector<InvalidatedRegion>, EngineError> PdfiumDocument::apply
|
||||
}
|
||||
|
||||
static const std::set<std::string> kContentOps = {
|
||||
"replace_text", "reflow_paragraph", "text_overlay", "add_text",
|
||||
"replace_text", "reflow_paragraph", "text_overlay", "add_text", "stamp",
|
||||
"underline", "strikeout", "squiggly", "redaction",
|
||||
"image_overlay", "highlight", "free_text", "comment", "freehand"};
|
||||
if (kContentOps.count(type)) markEdited(pageIndex);
|
||||
@@ -56,6 +56,8 @@ std::expected<std::vector<InvalidatedRegion>, EngineError> PdfiumDocument::apply
|
||||
r = applyOp_reflow(op, pageIndex);
|
||||
} else if (type == "text_overlay" || type == "add_text") {
|
||||
r = applyOp_textOverlay(op, pageIndex);
|
||||
} else if (type == "stamp") {
|
||||
r = applyOp_stamp(op, pageIndex);
|
||||
} else if (type == "underline" || type == "strikeout" || type == "squiggly") {
|
||||
r = applyOp_decoration(op, pageIndex);
|
||||
} else if (type == "redaction") {
|
||||
|
||||
@@ -1,4 +1,7 @@
|
||||
#include "parser/pdfium_internal.hpp"
|
||||
#include <chrono>
|
||||
#include <iomanip>
|
||||
#include <sstream>
|
||||
|
||||
namespace pdfengine::parser {
|
||||
|
||||
@@ -111,6 +114,101 @@ std::expected<void, EngineError> PdfiumDocument::applyOp_textOverlay(const nlohm
|
||||
#endif
|
||||
}
|
||||
|
||||
std::expected<void, EngineError> PdfiumDocument::applyOp_stamp(const nlohmann::json& op, int pageIndex) {
|
||||
#ifdef PDFENGINE_WITH_PDFIUM
|
||||
if (!op.contains("data") || !op["data"].is_object()) {
|
||||
spdlog::error("stamp operation missing 'data' object");
|
||||
return std::unexpected(EngineError::InvalidFormat);
|
||||
}
|
||||
auto data = op["data"];
|
||||
std::string text = data.value("text", "");
|
||||
double x = data.value("x", 0.0);
|
||||
double y = data.value("y", 0.0);
|
||||
double width = data.value("width", 100.0);
|
||||
double height = data.value("height", 30.0);
|
||||
double fontSize = data.value("fontSize", 18.0);
|
||||
std::string textColor = data.value("textColor", "#000000");
|
||||
std::string bgColor = data.value("backgroundColor", "#ffffff");
|
||||
std::string borderColor = data.value("borderColor", "#000000");
|
||||
bool includeDate = data.value("includeDate", false);
|
||||
|
||||
if (includeDate) {
|
||||
auto now = std::chrono::system_clock::now();
|
||||
auto in_time_t = std::chrono::system_clock::to_time_t(now);
|
||||
std::stringstream ss;
|
||||
ss << std::put_time(std::localtime(&in_time_t), "%Y-%m-%d %H:%M");
|
||||
text += "\n" + ss.str();
|
||||
}
|
||||
|
||||
FPDF_PAGE page = FPDF_LoadPage(doc_, pageIndex);
|
||||
if (!page) {
|
||||
spdlog::error("Failed to load page index {} for stamp", pageIndex);
|
||||
return std::unexpected(EngineError::Unknown);
|
||||
}
|
||||
|
||||
// Background rect
|
||||
FPDF_PAGEOBJECT bgRect = FPDFPageObj_CreateNewRect(
|
||||
static_cast<float>(x), static_cast<float>(y),
|
||||
static_cast<float>(width), static_cast<float>(height)
|
||||
);
|
||||
unsigned int r=0, g=0, b=0;
|
||||
parseHexColor(bgColor, r, g, b);
|
||||
FPDFPageObj_SetFillColor(bgRect, r, g, b, 255);
|
||||
FPDFPath_SetDrawMode(bgRect, FPDF_FILLMODE_WINDING, 0);
|
||||
FPDFPage_InsertObject(page, bgRect);
|
||||
|
||||
// Border rect
|
||||
FPDF_PAGEOBJECT borderRect = FPDFPageObj_CreateNewRect(
|
||||
static_cast<float>(x), static_cast<float>(y),
|
||||
static_cast<float>(width), static_cast<float>(height)
|
||||
);
|
||||
parseHexColor(borderColor, r, g, b);
|
||||
FPDFPageObj_SetStrokeColor(borderRect, r, g, b, 255);
|
||||
FPDFPageObj_SetStrokeWidth(borderRect, 2.5f);
|
||||
FPDFPath_SetDrawMode(borderRect, 0, 1);
|
||||
FPDFPage_InsertObject(page, borderRect);
|
||||
|
||||
FPDF_FONT font = FPDFText_LoadStandardFont(doc_, "Helvetica-Bold");
|
||||
|
||||
std::vector<std::string> lines;
|
||||
std::stringstream textStream(text);
|
||||
std::string line;
|
||||
while(std::getline(textStream, line, '\n')) {
|
||||
lines.push_back(line);
|
||||
}
|
||||
|
||||
float startY = static_cast<float>(y + height - fontSize * 1.1);
|
||||
parseHexColor(textColor, r, g, b);
|
||||
|
||||
for (size_t i = 0; i < lines.size(); i++) {
|
||||
float currentFontSize = static_cast<float>(i == 0 ? fontSize : fontSize * 0.5);
|
||||
FPDF_PAGEOBJECT textObj = FPDFPageObj_CreateTextObj(doc_, font, currentFontSize);
|
||||
FPDFPageObj_SetFillColor(textObj, r, g, b, 255);
|
||||
auto utf16 = utf8_to_utf16le(lines[i]);
|
||||
FPDFText_SetText(textObj, reinterpret_cast<FPDF_WIDESTRING>(utf16.data()));
|
||||
|
||||
float left=0, bottom=0, right=0, top=0;
|
||||
FPDFPageObj_GetBounds(textObj, &left, &bottom, &right, &top);
|
||||
float textWidth = right - left;
|
||||
|
||||
float textX = static_cast<float>(x + width / 2.0 - textWidth / 2.0);
|
||||
float textY = startY - (i * fontSize * 0.7f);
|
||||
|
||||
FPDFPageObj_Transform(textObj, 1.0, 0.0, 0.0, 1.0, textX, textY);
|
||||
FPDFPage_InsertObject(page, textObj);
|
||||
}
|
||||
|
||||
if (!FPDFPage_GenerateContent(page)) {
|
||||
spdlog::error("Failed to generate page content after stamp");
|
||||
}
|
||||
FPDF_ClosePage(page);
|
||||
return {};
|
||||
#else
|
||||
(void)op; (void)pageIndex;
|
||||
return std::unexpected(EngineError::Unknown);
|
||||
#endif
|
||||
}
|
||||
|
||||
std::expected<void, EngineError> PdfiumDocument::applyOp_decoration(const nlohmann::json& op, int pageIndex) {
|
||||
#ifdef PDFENGINE_WITH_PDFIUM
|
||||
std::string type = op.value("type", "");
|
||||
@@ -129,6 +227,7 @@ std::expected<void, EngineError> PdfiumDocument::applyOp_decoration(const nlohma
|
||||
int subtype = FPDF_ANNOT_UNDERLINE;
|
||||
if (type == "strikeout") subtype = FPDF_ANNOT_STRIKEOUT;
|
||||
else if (type == "squiggly") subtype = FPDF_ANNOT_SQUIGGLY;
|
||||
else if (type == "highlight") subtype = FPDF_ANNOT_HIGHLIGHT;
|
||||
|
||||
FPDF_ANNOTATION annot = FPDFPage_CreateAnnot(page, subtype);
|
||||
if (!annot) {
|
||||
@@ -383,6 +482,10 @@ std::expected<void, EngineError> PdfiumDocument::applyOp_freehand(const nlohmann
|
||||
float thickness = static_cast<float>(data.value("thickness", 2.0));
|
||||
FPDFAnnot_SetBorder(annot, 0.0f, 0.0f, thickness);
|
||||
|
||||
std::string tStr = std::to_string(thickness);
|
||||
auto tUtf16 = utf8_to_utf16le(tStr);
|
||||
FPDFAnnot_SetStringValue(annot, "CustomThickness", reinterpret_cast<FPDF_WIDESTRING>(tUtf16.data()));
|
||||
|
||||
float minX = 1e9f, minY = 1e9f, maxX = -1e9f, maxY = -1e9f;
|
||||
bool anyPoints = false;
|
||||
|
||||
@@ -549,6 +652,10 @@ std::expected<void, EngineError> PdfiumDocument::applyOp_updateAnnotation(const
|
||||
if (data.contains("thickness")) {
|
||||
float thickness = static_cast<float>(data["thickness"].get<double>());
|
||||
FPDFAnnot_SetBorder(targetAnnot, 0.0f, 0.0f, thickness);
|
||||
|
||||
std::string tStr = std::to_string(thickness);
|
||||
auto tUtf16 = utf8_to_utf16le(tStr);
|
||||
FPDFAnnot_SetStringValue(targetAnnot, "CustomThickness", reinterpret_cast<FPDF_WIDESTRING>(tUtf16.data()));
|
||||
}
|
||||
|
||||
if (data.contains("text")) {
|
||||
|
||||
@@ -600,6 +600,21 @@ std::expected<std::vector<PdfPage::AnnotationInfo>, EngineError> PdfiumPage::ext
|
||||
}
|
||||
|
||||
if (subtype == FPDF_ANNOT_INK) {
|
||||
float h_radius = 0, v_radius = 0, border_width = 1.0f;
|
||||
info.thickness = 2.0; // default
|
||||
|
||||
unsigned long ctLen = FPDFAnnot_GetStringValue(annot, "CustomThickness", nullptr, 0);
|
||||
if (ctLen > 2) {
|
||||
std::vector<char16_t> ctBuf(ctLen / 2);
|
||||
FPDFAnnot_GetStringValue(annot, "CustomThickness", reinterpret_cast<FPDF_WCHAR*>(ctBuf.data()), ctLen);
|
||||
std::string ctStr = utf16le_to_utf8(ctBuf.data(), ctBuf.size());
|
||||
try {
|
||||
info.thickness = std::stod(ctStr);
|
||||
} catch (...) {}
|
||||
} else if (FPDFAnnot_GetBorder(annot, &h_radius, &v_radius, &border_width)) {
|
||||
info.thickness = border_width;
|
||||
}
|
||||
|
||||
const double pageH = height();
|
||||
unsigned long strokeCount = FPDFAnnot_GetInkListCount(annot);
|
||||
for (unsigned long s = 0; s < strokeCount; ++s) {
|
||||
|
||||
Reference in New Issue
Block a user