dforge-cli 1.0.1__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,73 @@
1
+ from pathlib import Path
2
+
3
+ import questionary
4
+ from rich.console import Console
5
+
6
+ from dforge.operations import compress
7
+
8
+ from dforge.workflows.common import (
9
+ select_single_pdf,
10
+ success_screen,
11
+ get_output_name,
12
+ )
13
+
14
+ console = Console()
15
+
16
+
17
+ def compress_workflow():
18
+ console.print("\n[bold cyan]Compress PDF[/bold cyan]\n")
19
+
20
+ pdf = select_single_pdf()
21
+
22
+ if not pdf:
23
+ return
24
+
25
+ preset = questionary.select(
26
+ "Compression Preset",
27
+ choices=[
28
+ "screen",
29
+ "ebook",
30
+ "printer",
31
+ "prepress",
32
+ "default",
33
+ ],
34
+ ).ask()
35
+
36
+ output = get_output_name(
37
+ f"{pdf.stem}_compressed.pdf"
38
+ )
39
+
40
+ if not output:
41
+ return
42
+
43
+ output_path = Path(output)
44
+
45
+ console.print(
46
+ "\n[bold cyan]Compressing PDF...[/bold cyan]\n"
47
+ )
48
+
49
+ compress(
50
+ pdf,
51
+ output_path,
52
+ preset,
53
+ )
54
+
55
+ success_screen(
56
+ "Compression Complete",
57
+ output_file=output_path.name,
58
+ extra_lines=[
59
+ f"Preset : {preset}",
60
+ f"Location : {output_path.resolve()}",
61
+ ],
62
+ )
63
+
64
+ next_action = questionary.select(
65
+ "What next?",
66
+ choices=[
67
+ "Compress Another PDF",
68
+ "Back to PDF Tools",
69
+ ],
70
+ ).ask()
71
+
72
+ if next_action == "Compress Another PDF":
73
+ compress_workflow()
@@ -0,0 +1,148 @@
1
+ from pathlib import Path
2
+
3
+ import questionary
4
+ from rich.console import Console
5
+
6
+ from dforge.converter import (
7
+ convert,
8
+ images_to_pdf,
9
+ pdf_to_images,
10
+ )
11
+ from dforge.menu import conversion_menu
12
+ from dforge.workflows.common import success_screen
13
+
14
+ console = Console()
15
+
16
+
17
+ def markdown_to_pdf_workflow():
18
+ source = questionary.path(
19
+ "Markdown file:"
20
+ ).ask()
21
+
22
+ if not source:
23
+ return
24
+
25
+ convert(Path(source), "pdf")
26
+
27
+ success_screen(
28
+ "Conversion Complete"
29
+ )
30
+
31
+
32
+ def markdown_to_docx_workflow():
33
+ source = questionary.path(
34
+ "Markdown file:"
35
+ ).ask()
36
+
37
+ if not source:
38
+ return
39
+
40
+ convert(Path(source), "docx")
41
+
42
+ success_screen(
43
+ "Conversion Complete"
44
+ )
45
+
46
+
47
+ def docx_to_pdf_workflow():
48
+ source = questionary.path(
49
+ "DOCX file:"
50
+ ).ask()
51
+
52
+ if not source:
53
+ return
54
+
55
+ convert(Path(source), "pdf")
56
+
57
+ success_screen(
58
+ "Conversion Complete"
59
+ )
60
+
61
+
62
+ def docx_to_markdown_workflow():
63
+ source = questionary.path(
64
+ "DOCX file:"
65
+ ).ask()
66
+
67
+ if not source:
68
+ return
69
+
70
+ convert(Path(source), "md")
71
+
72
+ success_screen(
73
+ "Conversion Complete"
74
+ )
75
+
76
+
77
+ def images_to_pdf_workflow():
78
+ source = questionary.path(
79
+ "Image file or folder:"
80
+ ).ask()
81
+
82
+ if not source:
83
+ return
84
+
85
+ images_to_pdf(
86
+ Path(source)
87
+ )
88
+
89
+ success_screen(
90
+ "Conversion Complete"
91
+ )
92
+
93
+
94
+ def pdf_to_images_workflow():
95
+ source = questionary.path(
96
+ "PDF file:"
97
+ ).ask()
98
+
99
+ if not source:
100
+ return
101
+
102
+ fmt = questionary.select(
103
+ "Image format:",
104
+ choices=[
105
+ "png",
106
+ "jpeg",
107
+ "tiff",
108
+ ],
109
+ ).ask()
110
+
111
+ if not fmt:
112
+ return
113
+
114
+ pdf_to_images(
115
+ Path(source),
116
+ fmt=fmt,
117
+ )
118
+
119
+ success_screen(
120
+ "Conversion Complete"
121
+ )
122
+
123
+
124
+ def conversion_workflow():
125
+ while True:
126
+
127
+ choice = conversion_menu()
128
+
129
+ if choice == "Markdown → PDF":
130
+ markdown_to_pdf_workflow()
131
+
132
+ elif choice == "Markdown → DOCX":
133
+ markdown_to_docx_workflow()
134
+
135
+ elif choice == "DOCX → PDF":
136
+ docx_to_pdf_workflow()
137
+
138
+ elif choice == "DOCX → Markdown":
139
+ docx_to_markdown_workflow()
140
+
141
+ elif choice == "Images → PDF":
142
+ images_to_pdf_workflow()
143
+
144
+ elif choice == "PDF → Images":
145
+ pdf_to_images_workflow()
146
+
147
+ elif choice == "⬅ Back":
148
+ break
@@ -0,0 +1,50 @@
1
+ from pathlib import Path
2
+
3
+ import questionary
4
+ from rich.console import Console
5
+
6
+ from dforge.operations import decrypt
7
+
8
+ from dforge.workflows.common import (
9
+ select_single_pdf,
10
+ success_screen,
11
+ get_output_name,
12
+ )
13
+
14
+ console = Console()
15
+
16
+
17
+ def decrypt_workflow():
18
+ console.print("\n[bold cyan]Decrypt PDF[/bold cyan]\n")
19
+
20
+ pdf = select_single_pdf()
21
+
22
+ if not pdf:
23
+ return
24
+
25
+ password = questionary.password(
26
+ "Password:"
27
+ ).ask()
28
+
29
+ if not password:
30
+ return
31
+
32
+ output = get_output_name(
33
+ f"{pdf.stem}_decrypted.pdf"
34
+ )
35
+
36
+ if not output:
37
+ return
38
+
39
+ output_path = Path(output)
40
+
41
+ decrypt(
42
+ pdf,
43
+ password,
44
+ output_path,
45
+ )
46
+
47
+ success_screen(
48
+ "Decryption Complete",
49
+ output_file=output_path.name,
50
+ )
@@ -0,0 +1,50 @@
1
+ from pathlib import Path
2
+
3
+ import questionary
4
+ from rich.console import Console
5
+
6
+ from dforge.operations import encrypt
7
+
8
+ from dforge.workflows.common import (
9
+ select_single_pdf,
10
+ success_screen,
11
+ get_output_name,
12
+ )
13
+
14
+ console = Console()
15
+
16
+
17
+ def encrypt_workflow():
18
+ console.print("\n[bold cyan]Encrypt PDF[/bold cyan]\n")
19
+
20
+ pdf = select_single_pdf()
21
+
22
+ if not pdf:
23
+ return
24
+
25
+ password = questionary.password(
26
+ "Password:"
27
+ ).ask()
28
+
29
+ if not password:
30
+ return
31
+
32
+ output = get_output_name(
33
+ f"{pdf.stem}_encrypted.pdf"
34
+ )
35
+
36
+ if not output:
37
+ return
38
+
39
+ output_path = Path(output)
40
+
41
+ encrypt(
42
+ pdf,
43
+ password,
44
+ output_path,
45
+ )
46
+
47
+ success_screen(
48
+ "Encryption Complete",
49
+ output_file=output_path.name,
50
+ )
@@ -0,0 +1,18 @@
1
+ from dforge.menu import extract_menu
2
+
3
+
4
+ def extract_workflow():
5
+ while True:
6
+ choice = extract_menu()
7
+
8
+ if choice == "Extract Text":
9
+ pass
10
+
11
+ elif choice == "Extract Images":
12
+ pass
13
+
14
+ elif choice == "Extract Metadata":
15
+ pass
16
+
17
+ elif choice == "⬅ Back":
18
+ break
@@ -0,0 +1,21 @@
1
+ from dforge.menu import image_menu
2
+
3
+
4
+ def image_workflow():
5
+ while True:
6
+ choice = image_menu()
7
+
8
+ if choice == "Resize Images":
9
+ pass
10
+
11
+ elif choice == "Convert Format":
12
+ pass
13
+
14
+ elif choice == "Crop Images":
15
+ pass
16
+
17
+ elif choice == "Watermark Images":
18
+ pass
19
+
20
+ elif choice == "⬅ Back":
21
+ break
@@ -0,0 +1,109 @@
1
+ from pathlib import Path
2
+
3
+ import questionary
4
+ from rich.console import Console
5
+
6
+ from dforge.operations import merge
7
+
8
+ from dforge.workflows.common import (
9
+ select_multiple_pdfs,
10
+ success_screen,
11
+ get_output_name,
12
+ )
13
+
14
+ console = Console()
15
+
16
+
17
+ def merge_workflow():
18
+ console.print("\n[bold cyan]Merge PDFs[/bold cyan]\n")
19
+
20
+ folder, selected = select_multiple_pdfs()
21
+
22
+ if not folder or not selected:
23
+ return
24
+
25
+ if len(selected) < 2:
26
+ console.print(
27
+ "[red]Select at least 2 PDFs.[/red]"
28
+ )
29
+ return
30
+
31
+ console.print("\n[bold cyan]Selected PDFs[/bold cyan]\n")
32
+
33
+ for i, pdf in enumerate(selected, start=1):
34
+ console.print(f"{i}. {pdf}")
35
+
36
+ console.print(
37
+ f"\n[green]Total PDFs:[/green] {len(selected)}\n"
38
+ )
39
+
40
+ if not questionary.confirm(
41
+ "Continue?",
42
+ default=True,
43
+ ).ask():
44
+ return
45
+
46
+ sort_mode = questionary.select(
47
+ "Sort PDFs before merging?",
48
+ choices=[
49
+ "Keep Current Order",
50
+ "Alphabetical",
51
+ "Reverse Alphabetical",
52
+ ],
53
+ ).ask()
54
+
55
+ if sort_mode == "Alphabetical":
56
+ selected.sort()
57
+
58
+ elif sort_mode == "Reverse Alphabetical":
59
+ selected.sort(reverse=True)
60
+
61
+ output = get_output_name(
62
+ f"merged_{len(selected)}_files.pdf"
63
+ )
64
+
65
+ if not output:
66
+ return
67
+
68
+ output_path = Path(output)
69
+
70
+ if output_path.exists():
71
+
72
+ overwrite = questionary.confirm(
73
+ f"{output} already exists. Overwrite?",
74
+ default=False,
75
+ ).ask()
76
+
77
+ if not overwrite:
78
+ return
79
+
80
+ console.print(
81
+ "\n[bold cyan]Merging PDFs...[/bold cyan]\n"
82
+ )
83
+
84
+ inputs = [
85
+ folder / pdf
86
+ for pdf in selected
87
+ ]
88
+
89
+ merge(inputs, output_path)
90
+
91
+ success_screen(
92
+ "Merge Complete",
93
+ output_file=output_path.name,
94
+ extra_lines=[
95
+ f"Input Files : {len(selected)}",
96
+ f"Location : {output_path.resolve()}",
97
+ ],
98
+ )
99
+
100
+ next_action = questionary.select(
101
+ "What next?",
102
+ choices=[
103
+ "Merge More PDFs",
104
+ "Back to PDF Tools",
105
+ ],
106
+ ).ask()
107
+
108
+ if next_action == "Merge More PDFs":
109
+ merge_workflow()
@@ -0,0 +1,104 @@
1
+ from pathlib import Path
2
+
3
+ import questionary
4
+ from rich.console import Console
5
+ from dforge.loading import Loader
6
+ from dforge.engine import ocr_image, ocr_pdf
7
+ from dforge.dependencies import has_poppler
8
+ from dforge.workflows.common import (
9
+ success_screen,
10
+ get_output_name,
11
+ )
12
+ from dforge.dependencies import (
13
+ check_poppler,
14
+ check_tesseract,
15
+ )
16
+
17
+ console = Console()
18
+
19
+
20
+
21
+
22
+ def ocr_workflow():
23
+ if not check_tesseract():
24
+ return
25
+
26
+ input_file = questionary.path(
27
+ "Image or PDF file:"
28
+ ).ask()
29
+
30
+ if not input_file:
31
+ return
32
+
33
+ input_file = Path(input_file)
34
+
35
+ if input_file.suffix.lower() == ".pdf":
36
+ if not check_poppler():
37
+ return
38
+ console.print("\n[bold cyan]OCR Image / PDF[/bold cyan]\n")
39
+
40
+
41
+ if not input_file:
42
+ return
43
+
44
+ input_file = Path(input_file)
45
+
46
+ lang = questionary.text(
47
+ "OCR Language(s)",
48
+ default="eng",
49
+ ).ask()
50
+
51
+ fmt = questionary.select(
52
+ "Output Format",
53
+ choices=[
54
+ "txt",
55
+ "json",
56
+ "md",
57
+ ],
58
+ ).ask()
59
+
60
+ output = get_output_name(
61
+ f"{input_file.stem}_ocr.{fmt}"
62
+ )
63
+
64
+ if not output:
65
+ return
66
+
67
+ output_path = Path(output)
68
+
69
+
70
+ with Loader("Running OCR..."):
71
+ ocr_pdf(
72
+ input_file,
73
+ output_path,
74
+ lang,
75
+ )
76
+
77
+ if input_file.suffix.lower() == ".pdf":
78
+ ocr_pdf(
79
+ input_file,
80
+ output_path,
81
+ lang,
82
+ fmt,
83
+ )
84
+ else:
85
+ ocr_image(
86
+ input_file,
87
+ output_path,
88
+ lang,
89
+ fmt,
90
+ )
91
+
92
+ success_screen(
93
+ "OCR Complete",
94
+ output_file=output_path.name,
95
+ extra_lines=[
96
+ f"Format : {fmt}",
97
+ f"Lang : {lang}",
98
+ ],
99
+ )
100
+ if not has_poppler():
101
+ console.print(
102
+ "[red]Poppler not installed.[/red]"
103
+ )
104
+ return
File without changes
@@ -0,0 +1,57 @@
1
+ from pathlib import Path
2
+
3
+ import questionary
4
+ from rich.console import Console
5
+
6
+ from dforge.operations import extract_pages
7
+
8
+ from dforge.workflows.common import (
9
+ select_single_pdf,
10
+ success_screen,
11
+ get_output_name,
12
+ )
13
+
14
+ console = Console()
15
+
16
+
17
+ def pages_workflow():
18
+ console.print("\n[bold cyan]Extract Pages[/bold cyan]\n")
19
+
20
+ pdf = select_single_pdf()
21
+
22
+ if not pdf:
23
+ return
24
+
25
+ page_range = questionary.text(
26
+ 'Page range (Examples: 1-5, 3, 1,3,5)'
27
+ ).ask()
28
+
29
+ if not page_range:
30
+ return
31
+
32
+ output = get_output_name(
33
+ f"{pdf.stem}_pages.pdf"
34
+ )
35
+
36
+ if not output:
37
+ return
38
+
39
+ output_path = Path(output)
40
+
41
+ console.print(
42
+ "\n[bold cyan]Extracting Pages...[/bold cyan]\n"
43
+ )
44
+
45
+ extract_pages(
46
+ pdf,
47
+ page_range,
48
+ output_path,
49
+ )
50
+
51
+ success_screen(
52
+ "Page Extraction Complete",
53
+ output_file=output_path.name,
54
+ extra_lines=[
55
+ f"Pages : {page_range}",
56
+ ],
57
+ )
@@ -0,0 +1,53 @@
1
+ from pathlib import Path
2
+
3
+ import questionary
4
+ from rich.console import Console
5
+
6
+ from dforge.operations import rotate
7
+
8
+ from dforge.workflows.common import (
9
+ select_single_pdf,
10
+ success_screen,
11
+ get_output_name,
12
+ )
13
+
14
+ console = Console()
15
+
16
+
17
+ def rotate_workflow():
18
+ console.print("\n[bold cyan]Rotate PDF[/bold cyan]\n")
19
+
20
+ pdf = select_single_pdf()
21
+
22
+ if not pdf:
23
+ return
24
+
25
+ degrees = int(
26
+ questionary.select(
27
+ "Rotation",
28
+ choices=["90", "180", "270"],
29
+ ).ask()
30
+ )
31
+
32
+ output = get_output_name(
33
+ f"{pdf.stem}_rotated.pdf"
34
+ )
35
+
36
+ if not output:
37
+ return
38
+
39
+ output_path = Path(output)
40
+
41
+ rotate(
42
+ pdf,
43
+ degrees,
44
+ output_path,
45
+ )
46
+
47
+ success_screen(
48
+ "Rotation Complete",
49
+ output_file=output_path.name,
50
+ extra_lines=[
51
+ f"Rotation : {degrees}°",
52
+ ],
53
+ )