Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
b66b058
Add Add Attachment
datalogics-cgreen Jan 13, 2026
5642140
Add tests of Add Attachment
datalogics-cgreen Jan 13, 2026
d77d6d1
Add Add Image methods
datalogics-cgreen Jan 14, 2026
f7b9703
Add tests of Add Image tool
datalogics-cgreen Jan 14, 2026
3e348de
Add Add Text methods
datalogics-cgreen Jan 14, 2026
06e624b
Add tests of Add Text
datalogics-cgreen Jan 14, 2026
3b41fb1
Add to PDF tests: Fix testing guideline infractions
datalogics-cgreen Feb 6, 2026
af80d43
Replace test image file
datalogics-cgreen Feb 6, 2026
8b4be78
Ensure `text_objects` is stringified in testing
datalogics-cgreen Feb 6, 2026
aec924c
Ensure string values within `text_object` string
datalogics-cgreen Feb 6, 2026
5fceeeb
tests: fix instances where file ID generation attempted prefix of `3`
datalogics-cgreen Feb 11, 2026
38d8daa
tests: add async validation parity for add-to-pdf endpoints
datalogics-cgreen Feb 11, 2026
dd4e596
models: Type add-text color fields as fixed channel tuples
datalogics-cgreen Feb 12, 2026
6885f4c
_internal.py: Replace page number validator with stricter type check
datalogics-cgreen Feb 12, 2026
6c3a78f
public.py: Tighten Add Text typing
datalogics-cgreen Feb 12, 2026
eb2eefd
Rename public-facing `is_rtl` to `is_right_to_left`
datalogics-cgreen Feb 12, 2026
a68e908
Replace `json.dumps`
datalogics-cgreen Feb 12, 2026
24dd1d4
tests: cover add-text local validation branches
datalogics-cgreen Feb 12, 2026
bd49bed
tests: strengthen live add-to-pdf response assertions
datalogics-cgreen Feb 12, 2026
0d5939a
_internal.py: Remove RGB, CMYK validators
datalogics-cgreen Feb 12, 2026
60d15c1
public.py: Reject `str` values where only `float` should be expected
datalogics-cgreen Feb 12, 2026
3f9d6de
tests: Add `output` to Add Image, Add Text test payloads
datalogics-cgreen Feb 12, 2026
5e04b1e
tests: Round out test image formats with new inputs
datalogics-cgreen Feb 13, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
190 changes: 190 additions & 0 deletions src/pdfrest/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,9 @@
GifPdfRestPayload,
JpegPdfRestPayload,
OcrPdfPayload,
PdfAddAttachmentPayload,
PdfAddImagePayload,
PdfAddTextPayload,
PdfCompressPayload,
PdfDecryptPayload,
PdfEncryptPayload,
Expand Down Expand Up @@ -120,6 +123,7 @@
GraphicSmoothing,
JpegColorModel,
OcrLanguage,
PdfAddTextObject,
PdfAType,
PdfInfoQuery,
PdfMergeInput,
Expand Down Expand Up @@ -2547,6 +2551,72 @@ def apply_redactions(
timeout=timeout,
)

def add_text_to_pdf(
self,
file: PdfRestFile | Sequence[PdfRestFile],
*,
text_objects: PdfAddTextObject | Sequence[PdfAddTextObject],
output: str | None = None,
extra_query: Query | None = None,
extra_headers: AnyMapping | None = None,
extra_body: Body | None = None,
timeout: TimeoutTypes | None = None,
) -> PdfRestFileBasedResponse:
"""Insert one or more text blocks into a PDF."""

payload: dict[str, Any] = {
"files": file,
"text_objects": text_objects,
}
if output is not None:
payload["output"] = output

return self._post_file_operation(
endpoint="/pdf-with-added-text",
payload=payload,
payload_model=PdfAddTextPayload,
extra_query=extra_query,
extra_headers=extra_headers,
extra_body=extra_body,
timeout=timeout,
)

def add_image_to_pdf(
self,
file: PdfRestFile | Sequence[PdfRestFile],
*,
image: PdfRestFile | Sequence[PdfRestFile],
x: int,
y: int,
page: int,
output: str | None = None,
extra_query: Query | None = None,
extra_headers: AnyMapping | None = None,
extra_body: Body | None = None,
timeout: TimeoutTypes | None = None,
) -> PdfRestFileBasedResponse:
"""Insert an image into a single page of a PDF."""

payload: dict[str, Any] = {
"files": file,
"image": image,
"x": x,
"y": y,
"page": page,
}
if output is not None:
payload["output"] = output

return self._post_file_operation(
endpoint="/pdf-with-added-image",
payload=payload,
payload_model=PdfAddImagePayload,
extra_query=extra_query,
extra_headers=extra_headers,
extra_body=extra_body,
timeout=timeout,
)

def split_pdf(
self,
file: PdfRestFile | Sequence[PdfRestFile],
Expand Down Expand Up @@ -2973,6 +3043,33 @@ def compress_pdf(
timeout=timeout,
)

def add_attachment_to_pdf(
self,
file: PdfRestFile | Sequence[PdfRestFile],
*,
attachment: PdfRestFile | Sequence[PdfRestFile],
output: str | None = None,
extra_query: Query | None = None,
extra_headers: AnyMapping | None = None,
extra_body: Body | None = None,
timeout: TimeoutTypes | None = None,
) -> PdfRestFileBasedResponse:
"""Attach an uploaded file to a PDF."""

payload: dict[str, Any] = {"files": file, "attachment": attachment}
if output is not None:
payload["output"] = output

return self._post_file_operation(
endpoint="/pdf-with-added-attachment",
payload=payload,
payload_model=PdfAddAttachmentPayload,
extra_query=extra_query,
extra_headers=extra_headers,
extra_body=extra_body,
timeout=timeout,
)

def flatten_transparencies(
self,
file: PdfRestFile | Sequence[PdfRestFile],
Expand Down Expand Up @@ -3792,6 +3889,72 @@ async def apply_redactions(
timeout=timeout,
)

async def add_text_to_pdf(
self,
file: PdfRestFile | Sequence[PdfRestFile],
*,
text_objects: PdfAddTextObject | Sequence[PdfAddTextObject],
output: str | None = None,
extra_query: Query | None = None,
extra_headers: AnyMapping | None = None,
extra_body: Body | None = None,
timeout: TimeoutTypes | None = None,
) -> PdfRestFileBasedResponse:
"""Asynchronously insert text blocks into a PDF."""

payload: dict[str, Any] = {
"files": file,
"text_objects": text_objects,
}
if output is not None:
payload["output"] = output

return await self._post_file_operation(
endpoint="/pdf-with-added-text",
payload=payload,
payload_model=PdfAddTextPayload,
extra_query=extra_query,
extra_headers=extra_headers,
extra_body=extra_body,
timeout=timeout,
)

async def add_image_to_pdf(
self,
file: PdfRestFile | Sequence[PdfRestFile],
*,
image: PdfRestFile | Sequence[PdfRestFile],
x: int,
y: int,
page: int,
output: str | None = None,
extra_query: Query | None = None,
extra_headers: AnyMapping | None = None,
extra_body: Body | None = None,
timeout: TimeoutTypes | None = None,
) -> PdfRestFileBasedResponse:
"""Asynchronously insert an image into a PDF."""

payload: dict[str, Any] = {
"files": file,
"image": image,
"x": x,
"y": y,
"page": page,
}
if output is not None:
payload["output"] = output

return await self._post_file_operation(
endpoint="/pdf-with-added-image",
payload=payload,
payload_model=PdfAddImagePayload,
extra_query=extra_query,
extra_headers=extra_headers,
extra_body=extra_body,
timeout=timeout,
)

async def up(
self,
*,
Expand Down Expand Up @@ -4260,6 +4423,33 @@ async def compress_pdf(
timeout=timeout,
)

async def add_attachment_to_pdf(
self,
file: PdfRestFile | Sequence[PdfRestFile],
*,
attachment: PdfRestFile | Sequence[PdfRestFile],
output: str | None = None,
extra_query: Query | None = None,
extra_headers: AnyMapping | None = None,
extra_body: Body | None = None,
timeout: TimeoutTypes | None = None,
) -> PdfRestFileBasedResponse:
"""Asynchronously attach an uploaded file to a PDF."""

payload: dict[str, Any] = {"files": file, "attachment": attachment}
if output is not None:
payload["output"] = output

return await self._post_file_operation(
endpoint="/pdf-with-added-attachment",
payload=payload,
payload_model=PdfAddAttachmentPayload,
extra_query=extra_query,
extra_headers=extra_headers,
extra_body=extra_body,
timeout=timeout,
)

async def flatten_transparencies(
self,
file: PdfRestFile | Sequence[PdfRestFile],
Expand Down
Loading