modified: QUICKSTART.md
modified: app.py new file: start.bat modified: static/js/pdf-tools.js
This commit is contained in:
@@ -69,9 +69,20 @@ $env:PATH += ";C:\poppler\Library\bin"
|
|||||||
**Port bereits belegt?**
|
**Port bereits belegt?**
|
||||||
- Ändern Sie in app.py die Zeile: `app.run(debug=True, host='127.0.0.1', port=5001)`
|
- Ändern Sie in app.py die Zeile: `app.run(debug=True, host='127.0.0.1', port=5001)`
|
||||||
|
|
||||||
|
**PDF-Vorschau funktioniert nicht?**
|
||||||
|
```powershell
|
||||||
|
# Poppler installieren (für PDF-Vorschauen)
|
||||||
|
scoop install poppler
|
||||||
|
# ODER manuell von GitHub herunterladen und PATH hinzufügen
|
||||||
|
```
|
||||||
|
|
||||||
**Importfehler?**
|
**Importfehler?**
|
||||||
```powershell
|
```powershell
|
||||||
# Virtuelle Umgebung erneut aktivieren
|
# Virtuelle Umgebung erneut aktivieren
|
||||||
.\venv\Scripts\Activate.ps1
|
.\venv\Scripts\Activate.ps1
|
||||||
pip install --upgrade -r requirements.txt
|
pip install --upgrade -r requirements.txt
|
||||||
```
|
```
|
||||||
|
|
||||||
|
**Debug-Informationen:**
|
||||||
|
- Öffnen Sie http://127.0.0.1:5000/debug/check-dependencies
|
||||||
|
- Für PDF-spezifische Probleme: Browser-Konsole (F12) prüfen
|
||||||
176
app.py
176
app.py
@@ -205,8 +205,14 @@ def upload_pdf():
|
|||||||
page_count = len(pdf_reader.pages)
|
page_count = len(pdf_reader.pages)
|
||||||
|
|
||||||
# PDF Vorschau erstellen
|
# PDF Vorschau erstellen
|
||||||
|
print(f"Erstelle Vorschau für: {unique_filename}")
|
||||||
preview_filename = create_pdf_preview(unique_filename)
|
preview_filename = create_pdf_preview(unique_filename)
|
||||||
|
|
||||||
|
if preview_filename:
|
||||||
|
print(f"Vorschau erfolgreich erstellt: {preview_filename}")
|
||||||
|
else:
|
||||||
|
print("Vorschau-Erstellung fehlgeschlagen, verwende Fallback")
|
||||||
|
|
||||||
return jsonify({
|
return jsonify({
|
||||||
'success': True,
|
'success': True,
|
||||||
'filename': unique_filename,
|
'filename': unique_filename,
|
||||||
@@ -214,7 +220,8 @@ def upload_pdf():
|
|||||||
'page_count': page_count,
|
'page_count': page_count,
|
||||||
'size': os.path.getsize(file_path),
|
'size': os.path.getsize(file_path),
|
||||||
'preview': preview_filename,
|
'preview': preview_filename,
|
||||||
'rotation': 0 # Standardrotation
|
'rotation': 0, # Standardrotation
|
||||||
|
'has_preview': preview_filename is not None
|
||||||
})
|
})
|
||||||
|
|
||||||
return jsonify({'error': 'Nur PDF-Dateien sind erlaubt'}), 400
|
return jsonify({'error': 'Nur PDF-Dateien sind erlaubt'}), 400
|
||||||
@@ -227,22 +234,110 @@ def create_pdf_preview(pdf_filename):
|
|||||||
try:
|
try:
|
||||||
pdf_path = os.path.join(UPLOAD_FOLDER, pdf_filename)
|
pdf_path = os.path.join(UPLOAD_FOLDER, pdf_filename)
|
||||||
|
|
||||||
# PDF zu Bild konvertieren (nur erste Seite)
|
# Vorschau-Dateiname generieren
|
||||||
images = pdf2image.convert_from_path(pdf_path, first_page=1, last_page=1, dpi=150)
|
preview_filename = f"preview_{pdf_filename.rsplit('.', 1)[0]}.png"
|
||||||
|
preview_path = os.path.join(UPLOAD_FOLDER, preview_filename)
|
||||||
|
|
||||||
if images:
|
# PDF zu Bild konvertieren (nur erste Seite)
|
||||||
# Vorschau-Dateiname generieren
|
try:
|
||||||
preview_filename = f"preview_{pdf_filename.rsplit('.', 1)[0]}.png"
|
# Versuche mit pdf2image (benötigt Poppler)
|
||||||
preview_path = os.path.join(UPLOAD_FOLDER, preview_filename)
|
images = pdf2image.convert_from_path(
|
||||||
|
pdf_path,
|
||||||
|
first_page=1,
|
||||||
|
last_page=1,
|
||||||
|
dpi=150,
|
||||||
|
fmt='PNG'
|
||||||
|
)
|
||||||
|
|
||||||
# Bild speichern
|
if images:
|
||||||
images[0].save(preview_path, 'PNG')
|
# Bild speichern
|
||||||
return preview_filename
|
images[0].save(preview_path, 'PNG')
|
||||||
|
print(f"PDF-Vorschau erstellt: {preview_filename}")
|
||||||
|
return preview_filename
|
||||||
|
|
||||||
|
except ImportError:
|
||||||
|
print("pdf2image nicht verfügbar - PDF-Vorschau übersprungen")
|
||||||
|
return None
|
||||||
|
except Exception as pdf2image_error:
|
||||||
|
print(f"pdf2image Fehler: {str(pdf2image_error)}")
|
||||||
|
|
||||||
|
# Fallback: Versuche mit PyPDF2 + reportlab eine einfache Vorschau zu erstellen
|
||||||
|
try:
|
||||||
|
return create_simple_pdf_preview(pdf_path, preview_path, pdf_filename)
|
||||||
|
except Exception as fallback_error:
|
||||||
|
print(f"Fallback Fehler: {str(fallback_error)}")
|
||||||
|
return None
|
||||||
|
|
||||||
return None
|
return None
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
print(f"Fehler beim Erstellen der PDF-Vorschau: {str(e)}")
|
print(f"Allgemeiner Fehler beim Erstellen der PDF-Vorschau: {str(e)}")
|
||||||
|
return None
|
||||||
|
|
||||||
|
def create_simple_pdf_preview(pdf_path, preview_path, pdf_filename):
|
||||||
|
"""Erstellt eine einfache Text-basierte PDF-Vorschau als Fallback"""
|
||||||
|
try:
|
||||||
|
from PIL import Image, ImageDraw, ImageFont
|
||||||
|
|
||||||
|
# Lese PDF-Informationen
|
||||||
|
with open(pdf_path, 'rb') as pdf_file:
|
||||||
|
pdf_reader = PyPDF2.PdfReader(pdf_file)
|
||||||
|
page_count = len(pdf_reader.pages)
|
||||||
|
|
||||||
|
# Versuche Text der ersten Seite zu extrahieren
|
||||||
|
first_page_text = ""
|
||||||
|
if page_count > 0:
|
||||||
|
try:
|
||||||
|
first_page_text = pdf_reader.pages[0].extract_text()[:200]
|
||||||
|
except:
|
||||||
|
first_page_text = "PDF-Inhalt"
|
||||||
|
|
||||||
|
# Erstelle ein einfaches Vorschaubild
|
||||||
|
img = Image.new('RGB', (300, 400), color='white')
|
||||||
|
draw = ImageDraw.Draw(img)
|
||||||
|
|
||||||
|
# Versuche Standard-Font zu laden
|
||||||
|
try:
|
||||||
|
font = ImageFont.truetype("arial.ttf", 12)
|
||||||
|
title_font = ImageFont.truetype("arial.ttf", 16)
|
||||||
|
except:
|
||||||
|
font = ImageFont.load_default()
|
||||||
|
title_font = ImageFont.load_default()
|
||||||
|
|
||||||
|
# Zeichne PDF-Vorschau
|
||||||
|
draw.rectangle([(10, 10), (290, 390)], outline='black', width=2)
|
||||||
|
draw.text((20, 20), f"PDF: {pdf_filename}", fill='black', font=title_font)
|
||||||
|
draw.text((20, 50), f"Seiten: {page_count}", fill='gray', font=font)
|
||||||
|
|
||||||
|
# Text-Vorschau
|
||||||
|
if first_page_text:
|
||||||
|
# Text umbrechen
|
||||||
|
words = first_page_text.split()
|
||||||
|
lines = []
|
||||||
|
current_line = ""
|
||||||
|
for word in words[:50]: # Maximal 50 Wörter
|
||||||
|
if len(current_line + word) < 35:
|
||||||
|
current_line += word + " "
|
||||||
|
else:
|
||||||
|
lines.append(current_line.strip())
|
||||||
|
current_line = word + " "
|
||||||
|
if len(lines) >= 15: # Maximal 15 Zeilen
|
||||||
|
break
|
||||||
|
if current_line:
|
||||||
|
lines.append(current_line.strip())
|
||||||
|
|
||||||
|
y_pos = 80
|
||||||
|
for line in lines:
|
||||||
|
draw.text((20, y_pos), line, fill='black', font=font)
|
||||||
|
y_pos += 18
|
||||||
|
|
||||||
|
# Speichere Vorschaubild
|
||||||
|
img.save(preview_path, 'PNG')
|
||||||
|
print(f"Fallback PDF-Vorschau erstellt: {preview_path}")
|
||||||
|
return os.path.basename(preview_path)
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
print(f"Fehler bei Fallback-Vorschau: {str(e)}")
|
||||||
return None
|
return None
|
||||||
|
|
||||||
@app.route('/api/pdf-to-images', methods=['POST'])
|
@app.route('/api/pdf-to-images', methods=['POST'])
|
||||||
@@ -366,13 +461,72 @@ def serve_uploaded_file(filename):
|
|||||||
file_path = os.path.join(UPLOAD_FOLDER, filename)
|
file_path = os.path.join(UPLOAD_FOLDER, filename)
|
||||||
|
|
||||||
if not os.path.exists(file_path):
|
if not os.path.exists(file_path):
|
||||||
|
print(f"Datei nicht gefunden: {file_path}")
|
||||||
return "Datei nicht gefunden", 404
|
return "Datei nicht gefunden", 404
|
||||||
|
|
||||||
return send_file(file_path)
|
return send_file(file_path)
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
|
print(f"Fehler beim Servieren der Datei {filename}: {str(e)}")
|
||||||
return f"Fehler beim Laden der Datei: {str(e)}", 500
|
return f"Fehler beim Laden der Datei: {str(e)}", 500
|
||||||
|
|
||||||
|
@app.route('/debug/pdf-preview/<filename>')
|
||||||
|
def debug_pdf_preview(filename):
|
||||||
|
"""Debug-Route für PDF-Vorschau-Probleme"""
|
||||||
|
try:
|
||||||
|
pdf_path = os.path.join(UPLOAD_FOLDER, filename)
|
||||||
|
|
||||||
|
if not os.path.exists(pdf_path):
|
||||||
|
return jsonify({'error': f'PDF nicht gefunden: {pdf_path}'})
|
||||||
|
|
||||||
|
# Teste PDF-Vorschau-Erstellung
|
||||||
|
preview_filename = create_pdf_preview(filename)
|
||||||
|
|
||||||
|
return jsonify({
|
||||||
|
'pdf_file': filename,
|
||||||
|
'pdf_exists': os.path.exists(pdf_path),
|
||||||
|
'preview_created': preview_filename is not None,
|
||||||
|
'preview_filename': preview_filename,
|
||||||
|
'preview_path': os.path.join(UPLOAD_FOLDER, preview_filename) if preview_filename else None,
|
||||||
|
'preview_exists': os.path.exists(os.path.join(UPLOAD_FOLDER, preview_filename)) if preview_filename else False
|
||||||
|
})
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
return jsonify({'error': f'Debug-Fehler: {str(e)}'})
|
||||||
|
|
||||||
|
@app.route('/debug/check-dependencies')
|
||||||
|
def debug_check_dependencies():
|
||||||
|
"""Überprüft verfügbare Bibliotheken"""
|
||||||
|
deps = {}
|
||||||
|
|
||||||
|
try:
|
||||||
|
import pdf2image
|
||||||
|
deps['pdf2image'] = 'verfügbar'
|
||||||
|
# Teste Poppler
|
||||||
|
try:
|
||||||
|
pdf2image.convert_from_bytes(b'dummy')
|
||||||
|
except Exception as e:
|
||||||
|
if 'poppler' in str(e).lower():
|
||||||
|
deps['poppler'] = 'nicht gefunden'
|
||||||
|
else:
|
||||||
|
deps['poppler'] = 'möglicherweise verfügbar'
|
||||||
|
except ImportError:
|
||||||
|
deps['pdf2image'] = 'nicht installiert'
|
||||||
|
|
||||||
|
try:
|
||||||
|
import PyPDF2
|
||||||
|
deps['PyPDF2'] = 'verfügbar'
|
||||||
|
except ImportError:
|
||||||
|
deps['PyPDF2'] = 'nicht installiert'
|
||||||
|
|
||||||
|
try:
|
||||||
|
from PIL import Image
|
||||||
|
deps['Pillow'] = 'verfügbar'
|
||||||
|
except ImportError:
|
||||||
|
deps['Pillow'] = 'nicht installiert'
|
||||||
|
|
||||||
|
return jsonify(deps)
|
||||||
|
|
||||||
@app.route('/download/<filename>')
|
@app.route('/download/<filename>')
|
||||||
def download_file(filename):
|
def download_file(filename):
|
||||||
"""Download einer generierten Datei"""
|
"""Download einer generierten Datei"""
|
||||||
|
|||||||
84
start.bat
Normal file
84
start.bat
Normal file
@@ -0,0 +1,84 @@
|
|||||||
|
@echo off
|
||||||
|
echo ===============================================
|
||||||
|
echo PDF Editor Web App - Schnellstart
|
||||||
|
echo ===============================================
|
||||||
|
echo.
|
||||||
|
|
||||||
|
:: Zum Projektverzeichnis wechseln
|
||||||
|
cd /d "%~dp0"
|
||||||
|
|
||||||
|
:: Prüfen ob Python installiert ist
|
||||||
|
python --version >nul 2>&1
|
||||||
|
if errorlevel 1 (
|
||||||
|
echo [FEHLER] Python ist nicht installiert oder nicht im PATH!
|
||||||
|
echo Bitte installieren Sie Python 3.8+ von https://python.org
|
||||||
|
pause
|
||||||
|
exit /b 1
|
||||||
|
)
|
||||||
|
|
||||||
|
echo [INFO] Python gefunden:
|
||||||
|
python --version
|
||||||
|
|
||||||
|
:: Prüfen ob virtuelle Umgebung existiert
|
||||||
|
if not exist "venv\" (
|
||||||
|
echo [INFO] Erstelle virtuelle Umgebung...
|
||||||
|
python -m venv venv
|
||||||
|
if errorlevel 1 (
|
||||||
|
echo [FEHLER] Konnte virtuelle Umgebung nicht erstellen!
|
||||||
|
pause
|
||||||
|
exit /b 1
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
:: Virtuelle Umgebung aktivieren
|
||||||
|
echo [INFO] Aktiviere virtuelle Umgebung...
|
||||||
|
call venv\Scripts\activate.bat
|
||||||
|
|
||||||
|
:: Abhängigkeiten installieren falls requirements.txt existiert
|
||||||
|
if exist "requirements.txt" (
|
||||||
|
echo [INFO] Installiere/Update Abhängigkeiten...
|
||||||
|
pip install -r requirements.txt --quiet --disable-pip-version-check
|
||||||
|
if errorlevel 1 (
|
||||||
|
echo [WARNUNG] Einige Abhängigkeiten konnten nicht installiert werden.
|
||||||
|
echo Versuchen Sie: pip install -r requirements.txt
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
:: Prüfen ob notwendige Ordner existieren
|
||||||
|
if not exist "uploads\" mkdir uploads
|
||||||
|
if not exist "output\" mkdir output
|
||||||
|
|
||||||
|
:: Poppler-Check (für pdf2image)
|
||||||
|
echo [INFO] Prüfe Poppler-Installation...
|
||||||
|
python -c "import pdf2image; print('Poppler verfügbar')" 2>nul
|
||||||
|
if errorlevel 1 (
|
||||||
|
echo [WARNUNG] Poppler nicht gefunden! PDF-zu-Bild-Konvertierung funktioniert möglicherweise nicht.
|
||||||
|
echo Installieren Sie Poppler:
|
||||||
|
echo - Windows: scoop install poppler ODER manuell von GitHub
|
||||||
|
echo - Details siehe README_INSTALL.md
|
||||||
|
echo.
|
||||||
|
)
|
||||||
|
|
||||||
|
echo [INFO] Starte PDF Editor Web App...
|
||||||
|
echo [INFO] Die App wird unter http://127.0.0.1:5000 verfügbar sein
|
||||||
|
echo [INFO] Drücken Sie Ctrl+C zum Beenden
|
||||||
|
echo.
|
||||||
|
|
||||||
|
:: Flask App starten
|
||||||
|
python app.py
|
||||||
|
|
||||||
|
:: Falls Fehler beim Start
|
||||||
|
if errorlevel 1 (
|
||||||
|
echo.
|
||||||
|
echo [FEHLER] Die Anwendung konnte nicht gestartet werden!
|
||||||
|
echo Mögliche Lösungen:
|
||||||
|
echo 1. Prüfen Sie ob Port 5000 frei ist
|
||||||
|
echo 2. Installieren Sie Abhängigkeiten: pip install -r requirements.txt
|
||||||
|
echo 3. Überprüfen Sie die Fehlermeldungen oben
|
||||||
|
echo.
|
||||||
|
pause
|
||||||
|
)
|
||||||
|
|
||||||
|
echo.
|
||||||
|
echo Auf Wiedersehen!
|
||||||
|
pause
|
||||||
@@ -15,6 +15,11 @@ document.addEventListener('DOMContentLoaded', function() {
|
|||||||
initializeDOMElements();
|
initializeDOMElements();
|
||||||
setupEventListeners();
|
setupEventListeners();
|
||||||
setupDragAndDrop();
|
setupDragAndDrop();
|
||||||
|
|
||||||
|
// Überprüfe Abhängigkeiten beim Laden
|
||||||
|
setTimeout(() => {
|
||||||
|
checkDependencies();
|
||||||
|
}, 1000);
|
||||||
});
|
});
|
||||||
|
|
||||||
function initializeDOMElements() {
|
function initializeDOMElements() {
|
||||||
@@ -171,8 +176,9 @@ function createMergeFileItem(file, index) {
|
|||||||
// Create preview element
|
// Create preview element
|
||||||
const previewElement = file.preview ?
|
const previewElement = file.preview ?
|
||||||
`<img src="/uploads/${file.preview}" class="pdf-preview size-medium rotate-${file.rotation}"
|
`<img src="/uploads/${file.preview}" class="pdf-preview size-medium rotate-${file.rotation}"
|
||||||
alt="${file.original_name}" onclick="showPdfModal('${file.preview}', '${file.original_name}', ${index})">` :
|
alt="${file.original_name}" onclick="showPdfModal('${file.preview}', '${file.original_name}', ${index})"
|
||||||
`<div class="pdf-preview pdf-no-preview size-medium rotate-${file.rotation}">
|
onerror="handlePreviewError(this, '${file.original_name}')">` :
|
||||||
|
`<div class="pdf-preview pdf-no-preview size-medium rotate-${file.rotation}" title="Keine Vorschau verfügbar">
|
||||||
<i class="fas fa-file-pdf"></i>
|
<i class="fas fa-file-pdf"></i>
|
||||||
</div>`;
|
</div>`;
|
||||||
|
|
||||||
@@ -500,6 +506,54 @@ function showError(message) {
|
|||||||
errorArea.scrollIntoView({ behavior: 'smooth', block: 'center' });
|
errorArea.scrollIntoView({ behavior: 'smooth', block: 'center' });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function handlePreviewError(img, originalName) {
|
||||||
|
// Ersetze fehlgeschlagenes Bild durch Fallback
|
||||||
|
const container = img.parentElement;
|
||||||
|
container.innerHTML = `
|
||||||
|
<div class="pdf-preview pdf-no-preview size-medium" title="Vorschau nicht verfügbar">
|
||||||
|
<i class="fas fa-file-pdf"></i>
|
||||||
|
</div>
|
||||||
|
`;
|
||||||
|
|
||||||
|
console.warn(`PDF-Vorschau konnte nicht geladen werden: ${originalName}`);
|
||||||
|
showNotification(`Vorschau für ${originalName} nicht verfügbar`, 'warning');
|
||||||
|
}
|
||||||
|
|
||||||
|
// Debug-Funktion für PDF-Vorschau-Probleme
|
||||||
|
async function debugPdfPreview(filename) {
|
||||||
|
try {
|
||||||
|
const response = await fetch(`/debug/pdf-preview/${filename}`);
|
||||||
|
const data = await response.json();
|
||||||
|
console.log('PDF-Vorschau Debug:', data);
|
||||||
|
return data;
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Debug-Fehler:', error);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Überprüfe Abhängigkeiten
|
||||||
|
async function checkDependencies() {
|
||||||
|
try {
|
||||||
|
const response = await fetch('/debug/check-dependencies');
|
||||||
|
const data = await response.json();
|
||||||
|
console.log('Abhängigkeiten:', data);
|
||||||
|
|
||||||
|
// Warne bei fehlenden Abhängigkeiten
|
||||||
|
if (data.pdf2image !== 'verfügbar') {
|
||||||
|
showNotification('pdf2image nicht verfügbar - PDF-Vorschauen funktionieren möglicherweise nicht', 'warning');
|
||||||
|
}
|
||||||
|
if (data.poppler === 'nicht gefunden') {
|
||||||
|
showNotification('Poppler nicht gefunden - Installieren Sie Poppler für PDF-Vorschauen', 'warning');
|
||||||
|
}
|
||||||
|
|
||||||
|
return data;
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Abhängigkeits-Check fehlgeschlagen:', error);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Global functions
|
// Global functions
|
||||||
window.removeMergeFile = removeMergeFile;
|
window.removeMergeFile = removeMergeFile;
|
||||||
window.rotatePdf = rotatePdf;
|
window.rotatePdf = rotatePdf;
|
||||||
@@ -508,4 +562,7 @@ window.movePdfDown = movePdfDown;
|
|||||||
window.showPdfModal = showPdfModal;
|
window.showPdfModal = showPdfModal;
|
||||||
window.rotatePdfInModal = rotatePdfInModal;
|
window.rotatePdfInModal = rotatePdfInModal;
|
||||||
window.updatePdfPreviewSize = updatePdfPreviewSize;
|
window.updatePdfPreviewSize = updatePdfPreviewSize;
|
||||||
window.showSplitPdfModal = showSplitPdfModal;
|
window.showSplitPdfModal = showSplitPdfModal;
|
||||||
|
window.handlePreviewError = handlePreviewError;
|
||||||
|
window.debugPdfPreview = debugPdfPreview;
|
||||||
|
window.checkDependencies = checkDependencies;
|
||||||
Reference in New Issue
Block a user