Skip to content

Commit 278a73b

Browse files
authored
Merge pull request #111 from aspose-pdf-cloud/pdfcloud-4775-added-snippets-annotations
PDFCLOUD-4775: added snippets for Annotations
2 parents 64d5fd0 + afb378a commit 278a73b

11 files changed

+473
-0
lines changed
Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
1+
import shutil
2+
import json
3+
import logging
4+
import os
5+
from pathlib import Path
6+
from asposepdfcloud import ApiClient, PdfApi, HighlightAnnotation, Rectangle, Color, Point, AnnotationFlags, HorizontalAlignment, VerticalAlignment, AnnotationType
7+
8+
# Configure logging
9+
logging.basicConfig(level=logging.INFO, format="%(asctime)s - %(levelname)s - %(message)s")
10+
11+
12+
class Config:
13+
"""Configuration parameters."""
14+
CREDENTIALS_FILE = Path(r".\credentials.json")
15+
LOCAL_FOLDER = Path(r"C:\Samples")
16+
REMOTE_FOLDER = "Your_Temp_Pdf_Cloud"
17+
PDF_DOCUMENT_NAME = "sample.pdf"
18+
LOCAL_RESULT_DOCUMENT_NAME = "output_sample.pdf"
19+
PAGE_NUMBER = 1
20+
21+
ANNOTATION_ID = "GE5TAOZTHA2CYMRZGUWDIMBZFQZTEMA"
22+
23+
NEW_HL_ANNOTATION_TEXT = "NEW HIGHLIGHT TEXT ANNOTATION"
24+
NEW_HL_ANNOTATION_DESCRIPTION = 'This is a sample highlight annotation'
25+
NEW_HL_ANNOTATION_SUBJECT = "Highlight Text Box Subject"
26+
NEW_HL_ANNOTATION_CONTENTS = "Highlight annotation sample contents"
27+
28+
NEW_SO_ANNOTATION_TEXT = "NEW STRIKEOUT TEXT ANNOTATION"
29+
NEW_SO_ANNOTATION_DESCRIPTION = 'This is a sample strikeout annotation'
30+
NEW_SO_ANNOTATION_SUBJECT = "Strikeout Text Box Subject"
31+
NEW_SO_ANNOTATION_CONTENTS = "Strikeout annotation sample contents"
32+
33+
NEW_UL_ANNOTATION_TEXT = "NEW UNDERLINE TEXT ANNOTATION"
34+
NEW_UL_ANNOTATION_DESCRIPTION = 'This is a sample underline annotation'
35+
NEW_UL_ANNOTATION_SUBJECT = "Underline Text Box Subject"
36+
NEW_UL_ANNOTATION_CONTENTS = "Underline annotation sample contents"
37+
38+
NEW_FT_ANNOTATION_TEXT = "NEW FREE TEXT ANNOTATION"
39+
NEW_FT_ANNOTATION_DESCRIPTION = 'This is a sample annotation'
40+
NEW_FT_ANNOTATION_SUBJECT = "Free Text Box Subject"
41+
NEW_FT_ANNOTATION_CONTENTS = "Free Text annotation sample contents"
42+
43+
REPLACED_CONTENT = 'This is a replaced sample annotation'
44+
45+
class PdfAnnotationsHelper:
46+
def __init__(self, credentials_file: Path):
47+
self.pdf_api = None
48+
self._init_api(credentials_file)
49+
50+
def _init_api(self, credentials_file: Path):
51+
"""Initialize the API client."""
52+
try:
53+
with credentials_file.open("r", encoding="utf-8") as file:
54+
credentials = json.load(file)
55+
api_key, app_id = credentials.get("key"), credentials.get("id")
56+
if not api_key or not app_id:
57+
raise ValueError("Error: Missing API keys in the credentials file.")
58+
self.pdf_api = PdfApi(ApiClient(api_key, app_id))
59+
except (FileNotFoundError, json.JSONDecodeError, ValueError) as e:
60+
logging.error(f"Failed to load credentials: {e}")
61+
62+
def uploadFile(self, fileName: str, localFolder: Path, remoteFolder: str):
63+
""" Upload a local fileName to the Aspose Cloud server. """
64+
if self.pdf_api:
65+
file_path = localFolder / fileName
66+
try:
67+
self.pdf_api.upload_file(os.path.join(remoteFolder, fileName), file_path)
68+
logging.info(f"upload_file(): File '{fileName}' uploaded successfully.")
69+
except Exception as e:
70+
logging.error(f"upload_document(): Failed to upload file: {e}")
71+
72+
73+
def downloadFile(self, document: str, outputDocument: str, localFolder: Path, remoteFolder: Path, output_prefix: str):
74+
"""Download the processed PDF document from the Aspose Cloud server."""
75+
if self.pdf_api:
76+
try:
77+
temp_file = self.pdf_api.download_file(str(remoteFolder) + '/' + document)
78+
local_path = localFolder / ( output_prefix + outputDocument )
79+
shutil.move(temp_file, str(local_path))
80+
logging.info(f"download_result(): File successfully downloaded: {local_path}")
81+
except Exception as e:
82+
logging.error(f"download_result(): Failed to download file: {e}")
83+
84+
def delete_popup_annotations(self, parent_annotation):
85+
"""delete popup annotations for typed parent annotation in the page in the PDF document."""
86+
if self.pdf_api:
87+
args = {
88+
"folder": Config.REMOTE_FOLDER
89+
}
90+
response = self.pdf_api.get_document_popup_annotations(Config.PDF_DOCUMENT_NAME, **args)
91+
if response.code == 200:
92+
for annotation in response.annotations.list:
93+
if annotation.parent.id == parent_annotation:
94+
self.pdf_api.delete_annotation(Config.PDF_DOCUMENT_NAME, annotation.id, **args)
95+
logging.info(f"delete_popup_annotations(): popup annotation id = '{annotation.id}' for '{annotation.contents}' deleted in the document '{Config.PDF_DOCUMENT_NAME}'.")
96+
else:
97+
logging.error(f"delete_popup_annotations(): Failed to delete popup annotation in the document. Response code: {response.code}")
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
from annotations_helper import PdfAnnotationsHelper, Config
2+
from get_annotations import PdfGetAnnotations
3+
from get_annotation_by_id import PdfGetAnnotationById
4+
from new_highlight_annotation import PdfAddHighlightAnnotations
5+
from new_strikeout_annotation import PdfAddStrikeoutAnnotations
6+
from new_text_annotation import PdfAddFreeTextAnnotations
7+
from new_underline_annotation import PdfAddUnderlineAnnotations
8+
from delete_page_annotations import PdfDelPageAnnotations
9+
from delete_text_annotation import PdfDalTextAnnotations
10+
from replace_annotation import PdfReplaceAnnotations
11+
12+
if __name__ == "__main__":
13+
helper = PdfAnnotationsHelper(Config.CREDENTIALS_FILE)
14+
15+
modify_ant = PdfReplaceAnnotations(helper.pdf_api, helper)
16+
modify_ant.modify_annotation()
17+
18+
get_ant = PdfGetAnnotations(helper.pdf_api, helper)
19+
annotation_id =get_ant.request_annotations()
20+
21+
rq_ant = PdfGetAnnotationById(helper.pdf_api, helper)
22+
rq_ant.request_annotation(annotation_id)
23+
24+
del_ant = PdfDalTextAnnotations(helper.pdf_api, helper)
25+
del_ant.delete_annotation()
26+
27+
del_page_ant = PdfDelPageAnnotations(helper.pdf_api, helper)
28+
del_page_ant.delete_page_annotations()
29+
30+
add_hl = PdfAddHighlightAnnotations(helper.pdf_api, helper)
31+
add_hl.append_highlight_annotation()
32+
33+
add_so = PdfAddStrikeoutAnnotations(helper.pdf_api, helper)
34+
add_so.append_strikeout_annotation()
35+
36+
add_ft = PdfAddFreeTextAnnotations(helper.pdf_api, helper)
37+
add_ft.append_text_annotation()
38+
39+
add_ul = PdfAddUnderlineAnnotations(helper.pdf_api, helper)
40+
add_ul.append_underline_annotation()
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
2+
from annotations_helper import Config, PdfAnnotationsHelper, logging
3+
from asposepdfcloud import PdfApi
4+
5+
class PdfDelPageAnnotations:
6+
"""Class for managing PDF annotations using Aspose PDF Cloud API."""
7+
def __init__(self, pdf_api: PdfApi, helper: PdfAnnotationsHelper):
8+
self.pdfApi = pdf_api
9+
self.helper = helper
10+
11+
def delete_page_annotations(self):
12+
"""Delete annotation from the PDF document."""
13+
if self.pdfApi:
14+
self.helper.uploadFile(Config.PDF_DOCUMENT_NAME, Config.LOCAL_FOLDER, Config.REMOTE_FOLDER)
15+
16+
args = {
17+
"folder": Config.REMOTE_FOLDER
18+
}
19+
20+
response = self.pdfApi.delete_page_annotations(Config.PDF_DOCUMENT_NAME, Config.PAGE_NUMBER, **args)
21+
if response.code == 200:
22+
logging.info(f"delete_annotation(): annotations on page '{Config.PAGE_NUMBER}' deleted from the document '{Config.PDF_DOCUMENT_NAME}'.")
23+
self.helper.downloadFile(Config.PDF_DOCUMENT_NAME, Config.LOCAL_RESULT_DOCUMENT_NAME, Config.LOCAL_FOLDER, Config.REMOTE_FOLDER, "del_page_annotations_")
24+
else:
25+
logging.error(f"delete_annotation(): Failed to delete annotation from the document. Response code: {response.code}")
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
2+
from annotations_helper import Config, PdfAnnotationsHelper, logging
3+
from asposepdfcloud import PdfApi
4+
5+
class PdfDalTextAnnotations:
6+
"""Class for managing PDF annotations using Aspose PDF Cloud API."""
7+
def __init__(self, pdf_api: PdfApi, helper: PdfAnnotationsHelper):
8+
self.pdfApi = pdf_api
9+
self.helper = helper
10+
11+
def delete_annotation(self):
12+
"""Delete annotation from the PDF document."""
13+
if self.pdfApi:
14+
if Config.ANNOTATION_ID is None:
15+
logging.info(f"delete_annotation(): annotation id not defined!")
16+
return
17+
self.helper.uploadFile(Config.PDF_DOCUMENT_NAME, Config.LOCAL_FOLDER, Config.REMOTE_FOLDER)
18+
19+
args = {
20+
"folder": Config.REMOTE_FOLDER
21+
}
22+
response = self.pdfApi.delete_annotation(Config.PDF_DOCUMENT_NAME, Config.ANNOTATION_ID, **args)
23+
self.helper.delete_popup_annotations(Config.ANNOTATION_ID)
24+
if response.code == 200:
25+
logging.info(f"delete_annotation(): annotation '{Config.ANNOTATION_ID}' deleted from the document '{Config.PDF_DOCUMENT_NAME}'.")
26+
self.helper.downloadFile(Config.PDF_DOCUMENT_NAME, Config.LOCAL_RESULT_DOCUMENT_NAME, Config.LOCAL_FOLDER, Config.REMOTE_FOLDER, "del_annotation_")
27+
else:
28+
logging.error(f"delete_annotation(): Failed to delete annotation from the document. Response code: {response.code}")
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
from annotations_helper import Config, PdfAnnotationsHelper, logging
2+
from asposepdfcloud import PdfApi, AnnotationsInfoResponse
3+
4+
class PdfGetAnnotationById:
5+
"""Class for managing PDF annotations using Aspose PDF Cloud API."""
6+
def __init__(self, pdf_api: PdfApi, helper: PdfAnnotationsHelper):
7+
self.pdfApi = pdf_api
8+
self.helper = helper
9+
10+
def request_annotation(self, annotation_id):
11+
"""Get annotation from the page in the PDF document."""
12+
if self.pdfApi:
13+
self.helper.uploadFile(Config.PDF_DOCUMENT_NAME, Config.LOCAL_FOLDER, Config.REMOTE_FOLDER)
14+
15+
args = {
16+
"folder": Config.REMOTE_FOLDER
17+
}
18+
response = self.pdfApi.get_text_annotation(Config.PDF_DOCUMENT_NAME, annotation_id, **args)
19+
if response.code == 200:
20+
logging.info(f"get_annotationn(): annotation '{annotation_id}' successfully found '{response.annotation.contents}' in the document '{Config.PDF_DOCUMENT_NAME}'.")
21+
else:
22+
logging.error(f"get_annotation(): Failed to get annotation in the document. Response code: {response.code}")
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
from annotations_helper import Config, PdfAnnotationsHelper, logging
2+
from asposepdfcloud import PdfApi, AnnotationsInfoResponse
3+
4+
class PdfGetAnnotations:
5+
"""Class for managing PDF annotations using Aspose PDF Cloud API."""
6+
def __init__(self, pdf_api: PdfApi, helper: PdfAnnotationsHelper):
7+
self.pdfApi = pdf_api
8+
self.helper = helper
9+
10+
def request_annotations(self):
11+
"""Get annotations from the page in the PDF document."""
12+
if self.pdfApi:
13+
self.helper.uploadFile(Config.PDF_DOCUMENT_NAME, Config.LOCAL_FOLDER, Config.REMOTE_FOLDER)
14+
15+
args = {
16+
"folder": Config.REMOTE_FOLDER
17+
}
18+
annotation_result = ''
19+
response: AnnotationsInfoResponse = self.pdfApi.get_page_annotations(Config.PDF_DOCUMENT_NAME, Config.PAGE_NUMBER, **args)
20+
if response.code == 200:
21+
for annotation in response.annotations.list:
22+
if annotation.annotation_type == "Text":
23+
logging.info(f"get_annotations(): annotation id={annotation.id} with '{annotation.contents}' content get from the document '{Config.PDF_DOCUMENT_NAME}' on {annotation.page_index} page.")
24+
annotation_result = annotation.id
25+
return annotation_result
26+
else:
27+
logging.error(f"get_annotations(): Failed to get annotation in the document. Response code: {response.code}")
28+
return annotation_result
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
from annotations_helper import Config, PdfAnnotationsHelper, logging
2+
from asposepdfcloud import PdfApi, HighlightAnnotation, Rectangle, Color, Point, AnnotationFlags, HorizontalAlignment, VerticalAlignment
3+
4+
class PdfAddHighlightAnnotations:
5+
"""Class for managing PDF annotations using Aspose PDF Cloud API."""
6+
def __init__(self, pdf_api: PdfApi, helper: PdfAnnotationsHelper):
7+
self.pdfApi = pdf_api
8+
self.helper = helper
9+
10+
def append_highlight_annotation(self):
11+
"""Append a new highlight text annotation to the PDF document."""
12+
if self.pdfApi:
13+
self.helper.uploadFile(Config.PDF_DOCUMENT_NAME, Config.LOCAL_FOLDER, Config.REMOTE_FOLDER)
14+
15+
args = {
16+
"folder": Config.REMOTE_FOLDER
17+
}
18+
19+
new_annotation = HighlightAnnotation(
20+
rect = Rectangle(llx=100, lly=350, urx=450, ury=400),
21+
name = 'Highlight_Text_Annotation',
22+
flags = [AnnotationFlags.DEFAULT],
23+
horizontal_alignment = HorizontalAlignment.LEFT,
24+
vertical_alignment = VerticalAlignment.TOP,
25+
rich_text = Config.NEW_HL_ANNOTATION_TEXT,
26+
subject = Config.NEW_HL_ANNOTATION_SUBJECT,
27+
contents= Config.NEW_HL_ANNOTATION_CONTENTS,
28+
title = Config.NEW_HL_ANNOTATION_DESCRIPTION,
29+
z_index = 1,
30+
color=Color(a=0xFF, r=0, g=0xFF, b=0),
31+
quad_points = [
32+
Point(10, 10),
33+
Point(20, 10),
34+
Point(10, 20),
35+
Point(10, 10)
36+
],
37+
modified = '03/27/2025 00:00:00.000 AM',
38+
)
39+
try:
40+
response = self.pdfApi.post_page_highlight_annotations(Config.PDF_DOCUMENT_NAME, Config.PAGE_NUMBER, [new_annotation], **args)
41+
if response.code == 200:
42+
logging.info(f"append_highlight_annotation(): annotation '{Config.NEW_HL_ANNOTATION_TEXT}' added to the document '{Config.PDF_DOCUMENT_NAME}'.")
43+
self.helper.downloadFile(Config.PDF_DOCUMENT_NAME, Config.LOCAL_RESULT_DOCUMENT_NAME, Config.LOCAL_FOLDER, Config.REMOTE_FOLDER, "add_highlight_")
44+
else:
45+
logging.error(f"append_highlight_annotation(): Failed to add annotation to the document. Response code: {response.code}")
46+
except Exception as e:
47+
logging.error(f"append_highlight_annotation(): Error while adding annotation: {e}")
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
from annotations_helper import Config, PdfAnnotationsHelper, logging
2+
from asposepdfcloud import PdfApi, StrikeOutAnnotation, Rectangle, Color, Point, AnnotationFlags, HorizontalAlignment, VerticalAlignment
3+
4+
class PdfAddStrikeoutAnnotations:
5+
"""Class for managing PDF annotations using Aspose PDF Cloud API."""
6+
def __init__(self, pdf_api: PdfApi, helper: PdfAnnotationsHelper):
7+
self.pdfApi = pdf_api
8+
self.helper = helper
9+
10+
def append_strikeout_annotation(self):
11+
"""Append a new strikeout text annotation to the PDF document."""
12+
if self.pdfApi:
13+
self.helper.uploadFile(Config.PDF_DOCUMENT_NAME, Config.LOCAL_FOLDER, Config.REMOTE_FOLDER)
14+
15+
args = {
16+
"folder": Config.REMOTE_FOLDER
17+
}
18+
19+
new_annotation = StrikeOutAnnotation(
20+
rect = Rectangle(llx=100, lly=100, urx=200, ury=200),
21+
name = 'Strikeout_Text_Annotation',
22+
flags = [AnnotationFlags.DEFAULT],
23+
horizontal_alignment = HorizontalAlignment.LEFT,
24+
vertical_alignment = VerticalAlignment.TOP,
25+
rich_text = Config.NEW_SO_ANNOTATION_TEXT,
26+
subject = Config.NEW_SO_ANNOTATION_SUBJECT,
27+
title = Config.NEW_SO_ANNOTATION_DESCRIPTION,
28+
contents= Config.NEW_SO_ANNOTATION_CONTENTS,
29+
z_index = 1,
30+
color= Color(a=0xFF, r=0, g=0xFF, b=0),
31+
quad_points = [
32+
Point(10, 10),
33+
Point(20, 10),
34+
Point(10, 20),
35+
Point(10, 10)
36+
],
37+
modified = '03/27/2025 00:00:00.000 AM',
38+
)
39+
try:
40+
response = self.pdfApi.post_page_strike_out_annotations(Config.PDF_DOCUMENT_NAME, Config.PAGE_NUMBER, [new_annotation], **args)
41+
if response.code == 200:
42+
logging.info(f"append_strikeout_annotation(): annotation '{Config.NEW_SO_ANNOTATION_TEXT}' added to the document '{Config.PDF_DOCUMENT_NAME}'.")
43+
self.helper.downloadFile(Config.PDF_DOCUMENT_NAME, Config.LOCAL_RESULT_DOCUMENT_NAME, Config.LOCAL_FOLDER, Config.REMOTE_FOLDER, "add_strikeout_")
44+
else:
45+
logging.error(f"append_strikeout_annotation(): Failed to add annotation to the document. Response code: {response.code}")
46+
except Exception as e:
47+
logging.error(f"append_strikeout_annotation(): Error while adding annotation: {e}")

0 commit comments

Comments
 (0)