Spaces:
Sleeping
Sleeping
File size: 6,727 Bytes
0ac70f9 04b04af 0ac70f9 742f5dc 04b04af 742f5dc 5e3f9ac 0ac70f9 04b04af 0ac70f9 04b04af 0ac70f9 04b04af 2700cfa 04b04af 2700cfa 0ac70f9 04b04af 0ac70f9 04b04af 2700cfa 04b04af 2700cfa 04b04af d167a56 2700cfa 04b04af 2700cfa d167a56 2700cfa 04b04af 2700cfa 04b04af 5e3f9ac 2700cfa 04b04af 2700cfa 04b04af 2700cfa 04b04af 2700cfa 04b04af 2700cfa 04b04af 2700cfa 04b04af 2700cfa 04b04af 2700cfa 04b04af 2700cfa 04b04af 2700cfa 04b04af 2700cfa 04b04af 2700cfa 0ac70f9 2700cfa | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 | import os
import tempfile
import math
from typing import List, Tuple
import gradio as gr
from PyPDF2 import PdfReader, PdfWriter
# Load custom CSS
try:
with open(os.path.join(os.path.dirname(__file__), "fancy.css")) as f:
custom_css = f.read()
except FileNotFoundError:
custom_css = ""
# Maximum upload size (1 GB)
MAX_SIZE_BYTES = 1 * 1024 * 1024 * 1024
def split_pdf_into_chunks(file, num_chunks: int) -> Tuple[List[str], str]:
"""
Teilt eine PDF-Datei in X möglichst gleich große Teile auf.
Gibt eine Liste der temporären Dateipfade und eine Fehlermeldung (falls vorhanden) zurück.
"""
if file is None:
return [], "Bitte lade zuerst eine PDF-Datei hoch."
# Validate file size
file_size = os.path.getsize(file.name)
if file_size > MAX_SIZE_BYTES:
return [], f"Datei überschreitet das 1 GB Limit ({file_size / (1024*1024*1024):.2f} GB)."
if num_chunks < 1:
return [], "Die Anzahl der Teile muss mindestens 1 betragen."
try:
reader = PdfReader(file.name)
total_pages = len(reader.pages)
if total_pages == 0:
return [], "Die PDF-Datei enthält keine Seiten."
# Wenn mehr Teile gefordert sind als Seiten da sind, begrenzen wir es auf die Seitenzahl
chunks = min(num_chunks, total_pages)
# Berechne die Basis-Seitenanzahl pro Teil und den Rest
pages_per_chunk = total_pages // chunks
remainder = total_pages % chunks
output_files = []
current_page = 0
for i in range(chunks):
writer = PdfWriter()
# Verteile den Rest auf die ersten Chunks
actual_pages = pages_per_chunk + (1 if i < remainder else 0)
for _ in range(actual_pages):
writer.add_page(reader.pages[current_page])
current_page += 1
# Temporäre Datei für diesen Teil erstellen
# Verwende ein Muster im Namen, damit man die Reihenfolge erkennt
out_path = tempfile.NamedTemporaryFile(delete=False, suffix=f"_teil_{i+1}.pdf").name
with open(out_path, "wb") as f_out:
writer.write(f_out)
output_files.append(out_path)
return output_files, ""
except Exception as e:
return [], f"Fehler beim Aufteilen der PDF: {str(e)}"
def merge_pdfs(files):
# Merge multiple PDFs in upload order
if not files:
return None, "Bitte lade mindestens zwei PDF-Dateien zum Zusammenführen hoch."
# Validate total size
total_size = sum(os.path.getsize(f.name) for f in files)
if total_size > MAX_SIZE_BYTES:
return None, f"Gesamtgröße überschreitet das 1 GB Limit ({total_size / (1024*1024*1024):.2f} GB)."
writer = PdfWriter()
try:
for f in files:
reader = PdfReader(f.name)
for page in reader.pages:
writer.add_page(page)
except Exception as e:
return None, f"Fehler beim Lesen der PDFs: {e}"
out_path = tempfile.NamedTemporaryFile(delete=False, suffix=".pdf").name
with open(out_path, "wb") as f_out:
writer.write(f_out)
return out_path, None
# Build Gradio interface
with gr.Blocks(css=custom_css) as demo:
gr.HTML("<h1 id='header'>PDF Splitter & Merger</h1>")
gr.Markdown(
"**Schnelle & Lokale Lösung**: Verarbeite deine PDFs direkt im Speicher ohne dauerhafte Speicherung.\n"
"Nutze den **Split**-Tab, um eine PDF in gleich große Teile zu zerlegen, oder den **Merge**-Tab, um mehrere PDFs zu vereinen.\n\n"
"Maximale Dateigröße: **1 GB**."
)
with gr.Tabs():
# Split Tab
with gr.TabItem("PDF Aufteilen"):
with gr.Row(elem_classes="input-row"):
pdf_input = gr.File(label="PDF zum Aufteilen auswählen", file_types=['.pdf'])
chunks_input = gr.Number(label="In wie viele Teile aufteilen?", value=4, precision=0)
with gr.Row(elem_classes="button-row"):
split_button = gr.Button("PDF aufteilen", variant="primary")
# Wichtig: file_count="multiple" erlaubt die Anzeige von mehreren Download-Links
output_split = gr.File(label="Herunterladbare PDF-Teile", file_count="multiple")
error_split = gr.Textbox(label="Fehlermeldung", interactive=False, visible=False)
def run_split(file, chunks):
if file is None:
return None, "Bitte lade eine PDF-Datei hoch.", True
if chunks is None or chunks < 1:
return None, "Bitte gib eine gültige Anzahl an Teilen ein (mindestens 1).", True
out_paths, error = split_pdf_into_chunks(file, int(chunks))
if error:
return None, error, True
return out_paths, "", False
split_button.click(
fn=run_split,
inputs=[pdf_input, chunks_input],
outputs=[output_split, error_split, error_split],
api_name="split_pdf"
)
error_split.change(lambda msg: msg != "", inputs=error_split, outputs=error_split)
# Merge Tab
with gr.TabItem("PDF Zusammenführen"):
with gr.Row(elem_classes="input-row"):
merge_inputs = gr.Files(label="PDF-Dateien zum Zusammenführen auswählen", file_types=['.pdf'])
with gr.Row(elem_classes="button-row"):
merge_button = gr.Button("PDFs zusammenführen", variant="primary")
output_merge = gr.File(label="Zusammengeführte PDF herunterladen")
error_merge = gr.Textbox(label="Fehlermeldung", interactive=False, visible=False)
def run_merge(files):
if not files or len(files) < 2:
return None, "Bitte lade mindestens zwei PDF-Dateien hoch.", True
out_path, error = merge_pdfs(files)
if error:
return None, error, True
return out_path, "", False
merge_button.click(
fn=run_merge,
inputs=[merge_inputs],
outputs=[output_merge, error_merge, error_merge],
api_name="merge_pdfs"
)
error_merge.change(lambda msg: msg != "", inputs=error_merge, outputs=error_merge)
if __name__ == "__main__":
demo.launch(server_name="0.0.0.0", server_port=int(os.environ.get("PORT", 7860))) |