Merge branch 'dev' of https://gitea.maskantech.in/gitea_admin/pdf into azeem
This commit is contained in:
@@ -298,6 +298,22 @@ def get_font_bytes(document_id: str, internal_font_id: str) -> Response:
|
||||
)
|
||||
|
||||
|
||||
@router.get("/{document_id}/raw")
|
||||
def get_document_raw(document_id: str) -> Response:
|
||||
"""Raw PDF bytes of the current version — loaded into the in-browser WASM engine for the
|
||||
pixel-identical live-edit preview. Gated on copy permission (same as export)."""
|
||||
doc_info = document_store.get_document(document_id)
|
||||
if not doc_info:
|
||||
raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="Document not found")
|
||||
perms = doc_info.get("permissions") or {}
|
||||
if perms.get("canCopy", True) is False:
|
||||
raise HTTPException(status_code=status.HTTP_403_FORBIDDEN, detail="Not permitted (canCopy).")
|
||||
data = doc_info.get("bytes_data")
|
||||
if not data:
|
||||
raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="Document bytes unavailable")
|
||||
return Response(content=bytes(data), media_type="application/pdf")
|
||||
|
||||
|
||||
class SearchRect(BaseModel):
|
||||
x: float
|
||||
y: float
|
||||
|
||||
@@ -223,6 +223,41 @@ class ReplaceTextOperation(BaseModel):
|
||||
data: ReplaceTextData
|
||||
|
||||
|
||||
class ReflowRun(BaseModel):
|
||||
text: str
|
||||
internalFontId: str
|
||||
fontSize: float
|
||||
color: str = "#000000"
|
||||
|
||||
|
||||
class ReflowParagraphData(BaseModel):
|
||||
objectIndices: list[int]
|
||||
runs: list[ReflowRun]
|
||||
columnLeft: float
|
||||
columnRight: float
|
||||
firstBaselineY: float
|
||||
leading: float
|
||||
oldLineCount: int = 1
|
||||
align: Literal["left", "justify"] = "left"
|
||||
# Push-down column left edge (defaults to columnLeft). For a bullet item the text reflows from
|
||||
# a hanging indent (columnLeft) but the push-down spans the full width from pushColumnLeft so
|
||||
# bullet markers and items below move together.
|
||||
pushColumnLeft: float | None = None
|
||||
# Optional WYSIWYG mode: exact visual line breaks from the live editor (one inner list of
|
||||
# styled fragments per line). When present the engine emits these breaks verbatim.
|
||||
lines: list[list[ReflowRun]] | None = None
|
||||
# Optional WYSIWYG mode: exact visual line breaks from the live editor (one inner list of
|
||||
# styled fragments per line). When present the engine emits these breaks verbatim.
|
||||
lines: list[list[ReflowRun]] | None = None
|
||||
|
||||
|
||||
class ReflowParagraphOperation(BaseModel):
|
||||
id: str
|
||||
type: Literal["reflow_paragraph"]
|
||||
pageIndex: int = Field(..., ge=0)
|
||||
data: ReflowParagraphData
|
||||
|
||||
|
||||
class DecorationData(BaseModel):
|
||||
# Text-markup annotation (underline/strikeout/squiggly) over one or more text
|
||||
# lines — quadpoints in PDF top-down space, mirroring HighlightData.
|
||||
@@ -264,6 +299,7 @@ EditOperation = Annotated[
|
||||
| DeleteAnnotationOperation
|
||||
| UpdateAnnotationOperation
|
||||
| ReplaceTextOperation
|
||||
| ReflowParagraphOperation
|
||||
| UnderlineOperation
|
||||
| StrikeoutOperation
|
||||
| SquigglyOperation,
|
||||
@@ -283,7 +319,7 @@ _OP_PERMISSION = {
|
||||
"squiggly": "canAnnotate", "comment": "canAnnotate", "freehand": "canAnnotate",
|
||||
"free_text": "canAnnotate", "text_overlay": "canAnnotate", "image_overlay": "canAnnotate",
|
||||
"delete_annotation": "canAnnotate", "update_annotation": "canAnnotate",
|
||||
"replace_text": "canModify", "redaction": "canModify",
|
||||
"replace_text": "canModify", "reflow_paragraph": "canModify", "redaction": "canModify",
|
||||
"update_field": "canFillForms",
|
||||
"page_rotation": "canAssemble", "page_deletion": "canAssemble", "page_reorder": "canAssemble",
|
||||
}
|
||||
@@ -367,7 +403,7 @@ def apply_edits_impl(document_id: str, request: EditsRequest):
|
||||
|
||||
# Redaction and in-place text rewrites mutate existing objects, which do
|
||||
# not round-trip cleanly through an incremental save — force a full save.
|
||||
full_save_types = {"redaction", "replace_text"}
|
||||
full_save_types = {"redaction", "replace_text", "reflow_paragraph"}
|
||||
needs_full = any(op.get("type") in full_save_types for op in req_dict.get("operations", []))
|
||||
new_bytes = doc_copy.save_full() if needs_full else doc_copy.save_incremental()
|
||||
|
||||
|
||||
Reference in New Issue
Block a user