modified: QUICKSTART.md
modified: app.py deleted: output/.gitkeep modified: static/css/style.css modified: static/js/pdf-tools.js modified: templates/pdf_tools.html deleted: uploads/.gitkeep
This commit is contained in:
@@ -52,6 +52,10 @@ Die App läuft jetzt lokal auf Ihrem Computer. Sie können:
|
|||||||
- ✅ **NEU: Bildorientierung ändern** - 90°, 180°, 270° Rotation
|
- ✅ **NEU: Bildorientierung ändern** - 90°, 180°, 270° Rotation
|
||||||
- ✅ **NEU: Verschiedene Vorschaugrößen** - Klein, Mittel, Groß
|
- ✅ **NEU: Verschiedene Vorschaugrößen** - Klein, Mittel, Groß
|
||||||
- ✅ **NEU: Bildmodal** - Bilder in voller Größe anzeigen
|
- ✅ **NEU: Bildmodal** - Bilder in voller Größe anzeigen
|
||||||
|
- ✅ **NEU: PDF-Vorschau** - Erste Seite als Thumbnail anzeigen
|
||||||
|
- ✅ **NEU: PDF-Rotation** - PDFs vor dem Zusammenführen drehen
|
||||||
|
- ✅ **NEU: PDF-Reihenfolge** - PDFs durch Ziehen sortieren
|
||||||
|
- ✅ **NEU: PDF-Modal** - PDF-Seiten in voller Größe betrachten
|
||||||
- ✅ Vollständig offline arbeiten
|
- ✅ Vollständig offline arbeiten
|
||||||
|
|
||||||
## Bei Problemen:
|
## Bei Problemen:
|
||||||
|
|||||||
78
app.py
78
app.py
@@ -204,12 +204,17 @@ def upload_pdf():
|
|||||||
pdf_reader = PyPDF2.PdfReader(pdf_file)
|
pdf_reader = PyPDF2.PdfReader(pdf_file)
|
||||||
page_count = len(pdf_reader.pages)
|
page_count = len(pdf_reader.pages)
|
||||||
|
|
||||||
|
# PDF Vorschau erstellen
|
||||||
|
preview_filename = create_pdf_preview(unique_filename)
|
||||||
|
|
||||||
return jsonify({
|
return jsonify({
|
||||||
'success': True,
|
'success': True,
|
||||||
'filename': unique_filename,
|
'filename': unique_filename,
|
||||||
'original_name': filename,
|
'original_name': filename,
|
||||||
'page_count': page_count,
|
'page_count': page_count,
|
||||||
'size': os.path.getsize(file_path)
|
'size': os.path.getsize(file_path),
|
||||||
|
'preview': preview_filename,
|
||||||
|
'rotation': 0 # Standardrotation
|
||||||
})
|
})
|
||||||
|
|
||||||
return jsonify({'error': 'Nur PDF-Dateien sind erlaubt'}), 400
|
return jsonify({'error': 'Nur PDF-Dateien sind erlaubt'}), 400
|
||||||
@@ -217,6 +222,29 @@ def upload_pdf():
|
|||||||
except Exception as e:
|
except Exception as e:
|
||||||
return jsonify({'error': f'Fehler beim Upload: {str(e)}'}), 500
|
return jsonify({'error': f'Fehler beim Upload: {str(e)}'}), 500
|
||||||
|
|
||||||
|
def create_pdf_preview(pdf_filename):
|
||||||
|
"""Erstellt eine Vorschau der ersten PDF-Seite"""
|
||||||
|
try:
|
||||||
|
pdf_path = os.path.join(UPLOAD_FOLDER, pdf_filename)
|
||||||
|
|
||||||
|
# PDF zu Bild konvertieren (nur erste Seite)
|
||||||
|
images = pdf2image.convert_from_path(pdf_path, first_page=1, last_page=1, dpi=150)
|
||||||
|
|
||||||
|
if images:
|
||||||
|
# Vorschau-Dateiname generieren
|
||||||
|
preview_filename = f"preview_{pdf_filename.rsplit('.', 1)[0]}.png"
|
||||||
|
preview_path = os.path.join(UPLOAD_FOLDER, preview_filename)
|
||||||
|
|
||||||
|
# Bild speichern
|
||||||
|
images[0].save(preview_path, 'PNG')
|
||||||
|
return preview_filename
|
||||||
|
|
||||||
|
return None
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
print(f"Fehler beim Erstellen der PDF-Vorschau: {str(e)}")
|
||||||
|
return None
|
||||||
|
|
||||||
@app.route('/api/pdf-to-images', methods=['POST'])
|
@app.route('/api/pdf-to-images', methods=['POST'])
|
||||||
def pdf_to_images():
|
def pdf_to_images():
|
||||||
"""Konvertiert PDF zu Bildern"""
|
"""Konvertiert PDF zu Bildern"""
|
||||||
@@ -262,18 +290,31 @@ def merge_pdfs():
|
|||||||
"""Fügt mehrere PDFs zusammen"""
|
"""Fügt mehrere PDFs zusammen"""
|
||||||
try:
|
try:
|
||||||
data = request.get_json()
|
data = request.get_json()
|
||||||
filenames = data.get('filenames', [])
|
files_data = data.get('files', [])
|
||||||
|
|
||||||
if len(filenames) < 2:
|
if len(files_data) < 2:
|
||||||
return jsonify({'error': 'Mindestens 2 PDF-Dateien erforderlich'}), 400
|
return jsonify({'error': 'Mindestens 2 PDF-Dateien erforderlich'}), 400
|
||||||
|
|
||||||
# PDF Merger erstellen
|
# PDF Merger erstellen
|
||||||
merger = PyPDF2.PdfMerger()
|
merger = PyPDF2.PdfMerger()
|
||||||
|
|
||||||
for filename in filenames:
|
for file_data in files_data:
|
||||||
|
filename = file_data.get('filename')
|
||||||
|
rotation = file_data.get('rotation', 0)
|
||||||
|
|
||||||
file_path = os.path.join(UPLOAD_FOLDER, filename)
|
file_path = os.path.join(UPLOAD_FOLDER, filename)
|
||||||
if os.path.exists(file_path):
|
if os.path.exists(file_path):
|
||||||
merger.append(file_path)
|
if rotation != 0:
|
||||||
|
# PDF mit Rotation erstellen
|
||||||
|
rotated_pdf_path = create_rotated_pdf(file_path, rotation)
|
||||||
|
if rotated_pdf_path:
|
||||||
|
merger.append(rotated_pdf_path)
|
||||||
|
# Temporäre rotierte PDF löschen nach dem Hinzufügen
|
||||||
|
os.remove(rotated_pdf_path)
|
||||||
|
else:
|
||||||
|
merger.append(file_path) # Fallback ohne Rotation
|
||||||
|
else:
|
||||||
|
merger.append(file_path)
|
||||||
|
|
||||||
# Zusammengeführte PDF speichern
|
# Zusammengeführte PDF speichern
|
||||||
output_filename = f"merged_pdf_{str(uuid.uuid4())[:8]}.pdf"
|
output_filename = f"merged_pdf_{str(uuid.uuid4())[:8]}.pdf"
|
||||||
@@ -287,12 +328,37 @@ def merge_pdfs():
|
|||||||
return jsonify({
|
return jsonify({
|
||||||
'success': True,
|
'success': True,
|
||||||
'filename': output_filename,
|
'filename': output_filename,
|
||||||
'message': f'{len(filenames)} PDFs erfolgreich zusammengeführt'
|
'message': f'{len(files_data)} PDFs erfolgreich zusammengeführt'
|
||||||
})
|
})
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
return jsonify({'error': f'Fehler beim Zusammenführen: {str(e)}'}), 500
|
return jsonify({'error': f'Fehler beim Zusammenführen: {str(e)}'}), 500
|
||||||
|
|
||||||
|
def create_rotated_pdf(pdf_path, rotation):
|
||||||
|
"""Erstellt eine rotierte Version der PDF"""
|
||||||
|
try:
|
||||||
|
# Temporären Dateinamen für rotierte PDF erstellen
|
||||||
|
temp_filename = f"temp_rotated_{str(uuid.uuid4())[:8]}.pdf"
|
||||||
|
temp_path = os.path.join(UPLOAD_FOLDER, temp_filename)
|
||||||
|
|
||||||
|
with open(pdf_path, 'rb') as input_file:
|
||||||
|
pdf_reader = PyPDF2.PdfReader(input_file)
|
||||||
|
pdf_writer = PyPDF2.PdfWriter()
|
||||||
|
|
||||||
|
for page in pdf_reader.pages:
|
||||||
|
# Seite rotieren
|
||||||
|
rotated_page = page.rotate(rotation)
|
||||||
|
pdf_writer.add_page(rotated_page)
|
||||||
|
|
||||||
|
with open(temp_path, 'wb') as output_file:
|
||||||
|
pdf_writer.write(output_file)
|
||||||
|
|
||||||
|
return temp_path
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
print(f"Fehler beim Rotieren der PDF: {str(e)}")
|
||||||
|
return None
|
||||||
|
|
||||||
@app.route('/uploads/<filename>')
|
@app.route('/uploads/<filename>')
|
||||||
def serve_uploaded_file(filename):
|
def serve_uploaded_file(filename):
|
||||||
"""Serviert hochgeladene Dateien für die Vorschau"""
|
"""Serviert hochgeladene Dateien für die Vorschau"""
|
||||||
|
|||||||
@@ -1,2 +0,0 @@
|
|||||||
# Diese Datei sorgt dafür, dass der output Ordner in Git erhalten bleibt
|
|
||||||
# Der Ordnerinhalt wird durch .gitignore ignoriert
|
|
||||||
@@ -485,6 +485,75 @@ footer {
|
|||||||
object-fit: contain;
|
object-fit: contain;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* PDF Preview */
|
||||||
|
.pdf-preview {
|
||||||
|
max-width: 120px;
|
||||||
|
max-height: 120px;
|
||||||
|
object-fit: cover;
|
||||||
|
border-radius: var(--border-radius);
|
||||||
|
border: 2px solid #e9ecef;
|
||||||
|
transition: all 0.3s ease;
|
||||||
|
cursor: pointer;
|
||||||
|
background-color: #f8f9fa;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pdf-preview:hover {
|
||||||
|
border-color: var(--danger-color);
|
||||||
|
transform: scale(1.05);
|
||||||
|
}
|
||||||
|
|
||||||
|
.pdf-preview.size-small {
|
||||||
|
max-width: 80px;
|
||||||
|
max-height: 80px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pdf-preview.size-medium {
|
||||||
|
max-width: 120px;
|
||||||
|
max-height: 120px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pdf-preview.size-large {
|
||||||
|
max-width: 160px;
|
||||||
|
max-height: 160px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* PDF item enhanced */
|
||||||
|
.pdf-item-enhanced {
|
||||||
|
padding: 1rem;
|
||||||
|
border-radius: var(--border-radius);
|
||||||
|
transition: all 0.3s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pdf-item-enhanced:hover {
|
||||||
|
background-color: rgba(220, 53, 69, 0.05);
|
||||||
|
transform: translateY(-2px);
|
||||||
|
box-shadow: var(--box-shadow-lg);
|
||||||
|
}
|
||||||
|
|
||||||
|
.pdf-info {
|
||||||
|
flex: 1;
|
||||||
|
min-width: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pdf-controls {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 0.5rem;
|
||||||
|
align-items: flex-end;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* PDF no-preview fallback */
|
||||||
|
.pdf-no-preview {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
background-color: #f8f9fa;
|
||||||
|
border: 2px dashed #dee2e6;
|
||||||
|
border-radius: var(--border-radius);
|
||||||
|
color: var(--danger-color);
|
||||||
|
font-size: 2rem;
|
||||||
|
}
|
||||||
|
|
||||||
/* File item enhanced */
|
/* File item enhanced */
|
||||||
.file-item-enhanced {
|
.file-item-enhanced {
|
||||||
padding: 1rem;
|
padding: 1rem;
|
||||||
|
|||||||
@@ -160,22 +160,56 @@ function displayMergeFiles() {
|
|||||||
|
|
||||||
function createMergeFileItem(file, index) {
|
function createMergeFileItem(file, index) {
|
||||||
const div = document.createElement('div');
|
const div = document.createElement('div');
|
||||||
div.className = 'list-group-item';
|
div.className = 'list-group-item pdf-item-enhanced';
|
||||||
div.dataset.index = index;
|
div.dataset.index = index;
|
||||||
|
|
||||||
|
// Initialize rotation if not set
|
||||||
|
if (file.rotation === undefined) {
|
||||||
|
file.rotation = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create preview element
|
||||||
|
const previewElement = file.preview ?
|
||||||
|
`<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})">` :
|
||||||
|
`<div class="pdf-preview pdf-no-preview size-medium rotate-${file.rotation}">
|
||||||
|
<i class="fas fa-file-pdf"></i>
|
||||||
|
</div>`;
|
||||||
|
|
||||||
div.innerHTML = `
|
div.innerHTML = `
|
||||||
<div class="d-flex align-items-center">
|
<div class="d-flex align-items-center">
|
||||||
<div class="file-icon me-3">
|
<div class="pdf-preview-container me-3">
|
||||||
<i class="fas fa-file-pdf text-danger fa-2x"></i>
|
${previewElement}
|
||||||
</div>
|
</div>
|
||||||
<div class="flex-grow-1">
|
<div class="pdf-info">
|
||||||
<div class="file-name fw-bold">${file.original_name}</div>
|
<div class="file-name fw-bold">${file.original_name}</div>
|
||||||
<div class="file-details text-muted">
|
<div class="file-details text-muted">
|
||||||
${file.page_count} Seiten • ${formatFileSize(file.size)}
|
${file.page_count} Seiten • ${formatFileSize(file.size)}
|
||||||
</div>
|
</div>
|
||||||
|
<div class="rotation-controls">
|
||||||
|
<button type="button" class="btn btn-sm btn-outline-danger rotation-btn"
|
||||||
|
onclick="rotatePdf(${index}, -90)" title="Links drehen">
|
||||||
|
<i class="fas fa-undo"></i>
|
||||||
|
</button>
|
||||||
|
<button type="button" class="btn btn-sm btn-outline-danger rotation-btn"
|
||||||
|
onclick="rotatePdf(${index}, 90)" title="Rechts drehen">
|
||||||
|
<i class="fas fa-redo"></i>
|
||||||
|
</button>
|
||||||
|
<small class="text-muted ms-2">${file.rotation}°</small>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="file-actions">
|
<div class="pdf-controls">
|
||||||
<button type="button" class="btn btn-sm btn-outline-danger" onclick="removeMergeFile(${index})">
|
<div class="d-flex gap-1 mb-2">
|
||||||
|
<button type="button" class="btn btn-sm btn-outline-secondary" onclick="movePdfUp(${index})"
|
||||||
|
${index === 0 ? 'disabled' : ''} title="Nach oben">
|
||||||
|
<i class="fas fa-arrow-up"></i>
|
||||||
|
</button>
|
||||||
|
<button type="button" class="btn btn-sm btn-outline-secondary" onclick="movePdfDown(${index})"
|
||||||
|
${index === pdfToolsFiles.length - 1 ? 'disabled' : ''} title="Nach unten">
|
||||||
|
<i class="fas fa-arrow-down"></i>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<button type="button" class="btn btn-sm btn-outline-danger" onclick="removeMergeFile(${index})" title="Entfernen">
|
||||||
<i class="fas fa-trash"></i>
|
<i class="fas fa-trash"></i>
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
@@ -210,6 +244,108 @@ function removeMergeFile(index) {
|
|||||||
showNotification('PDF-Datei entfernt.', 'info');
|
showNotification('PDF-Datei entfernt.', 'info');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function rotatePdf(index, degrees) {
|
||||||
|
if (index >= 0 && index < pdfToolsFiles.length) {
|
||||||
|
pdfToolsFiles[index].rotation = (pdfToolsFiles[index].rotation + degrees) % 360;
|
||||||
|
if (pdfToolsFiles[index].rotation < 0) {
|
||||||
|
pdfToolsFiles[index].rotation += 360;
|
||||||
|
}
|
||||||
|
displayMergeFiles();
|
||||||
|
showNotification(`PDF um ${degrees}° gedreht.`, 'info');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function movePdfUp(index) {
|
||||||
|
if (index > 0) {
|
||||||
|
[pdfToolsFiles[index], pdfToolsFiles[index - 1]] = [pdfToolsFiles[index - 1], pdfToolsFiles[index]];
|
||||||
|
displayMergeFiles();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function movePdfDown(index) {
|
||||||
|
if (index < pdfToolsFiles.length - 1) {
|
||||||
|
[pdfToolsFiles[index], pdfToolsFiles[index + 1]] = [pdfToolsFiles[index + 1], pdfToolsFiles[index]];
|
||||||
|
displayMergeFiles();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function showPdfModal(previewFilename, originalName, index) {
|
||||||
|
// Create modal if it doesn't exist
|
||||||
|
let modal = document.getElementById('pdf-modal');
|
||||||
|
if (!modal) {
|
||||||
|
modal = document.createElement('div');
|
||||||
|
modal.className = 'modal fade image-modal';
|
||||||
|
modal.id = 'pdf-modal';
|
||||||
|
modal.setAttribute('tabindex', '-1');
|
||||||
|
modal.setAttribute('aria-hidden', 'true');
|
||||||
|
|
||||||
|
modal.innerHTML = `
|
||||||
|
<div class="modal-dialog modal-lg modal-dialog-centered">
|
||||||
|
<div class="modal-content">
|
||||||
|
<div class="modal-header">
|
||||||
|
<h5 class="modal-title" id="pdf-modal-title">${originalName}</h5>
|
||||||
|
<button type="button" class="btn-close" data-bs-dismiss="modal"></button>
|
||||||
|
</div>
|
||||||
|
<div class="modal-body">
|
||||||
|
<img id="modal-pdf-preview" src="/uploads/${previewFilename}"
|
||||||
|
class="img-fluid rotate-${pdfToolsFiles[index].rotation}" alt="${originalName}">
|
||||||
|
<p class="text-muted mt-2 mb-0">Vorschau der ersten Seite</p>
|
||||||
|
</div>
|
||||||
|
<div class="modal-footer">
|
||||||
|
<div class="btn-group me-auto">
|
||||||
|
<button type="button" class="btn btn-outline-danger" onclick="rotatePdfInModal(${index}, -90)">
|
||||||
|
<i class="fas fa-undo me-1"></i>Links drehen
|
||||||
|
</button>
|
||||||
|
<button type="button" class="btn btn-outline-danger" onclick="rotatePdfInModal(${index}, 90)">
|
||||||
|
<i class="fas fa-redo me-1"></i>Rechts drehen
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Schließen</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
`;
|
||||||
|
|
||||||
|
document.body.appendChild(modal);
|
||||||
|
} else {
|
||||||
|
// Update existing modal
|
||||||
|
document.getElementById('pdf-modal-title').textContent = originalName;
|
||||||
|
const modalPreview = document.getElementById('modal-pdf-preview');
|
||||||
|
modalPreview.src = `/uploads/${previewFilename}`;
|
||||||
|
modalPreview.alt = originalName;
|
||||||
|
modalPreview.className = `img-fluid rotate-${pdfToolsFiles[index].rotation}`;
|
||||||
|
|
||||||
|
// Update rotation buttons
|
||||||
|
const rotateButtons = modal.querySelectorAll('.btn-outline-danger');
|
||||||
|
rotateButtons[0].onclick = () => rotatePdfInModal(index, -90);
|
||||||
|
rotateButtons[1].onclick = () => rotatePdfInModal(index, 90);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Show modal
|
||||||
|
const bootstrapModal = new bootstrap.Modal(modal);
|
||||||
|
bootstrapModal.show();
|
||||||
|
}
|
||||||
|
|
||||||
|
function rotatePdfInModal(index, degrees) {
|
||||||
|
rotatePdf(index, degrees);
|
||||||
|
|
||||||
|
// Update modal preview
|
||||||
|
const modalPreview = document.getElementById('modal-pdf-preview');
|
||||||
|
modalPreview.className = `img-fluid rotate-${pdfToolsFiles[index].rotation}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
function updatePdfPreviewSize() {
|
||||||
|
const previewSize = document.getElementById('pdf-preview-size')?.value || 'medium';
|
||||||
|
const previews = document.querySelectorAll('.pdf-preview');
|
||||||
|
|
||||||
|
previews.forEach(preview => {
|
||||||
|
// Remove existing size classes
|
||||||
|
preview.classList.remove('size-small', 'size-medium', 'size-large');
|
||||||
|
// Add new size class
|
||||||
|
preview.classList.add('size-' + previewSize);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
async function mergePdfs() {
|
async function mergePdfs() {
|
||||||
if (pdfToolsFiles.length < 2) {
|
if (pdfToolsFiles.length < 2) {
|
||||||
showError('Mindestens 2 PDF-Dateien erforderlich.');
|
showError('Mindestens 2 PDF-Dateien erforderlich.');
|
||||||
@@ -220,11 +356,16 @@ async function mergePdfs() {
|
|||||||
processingModal.show();
|
processingModal.show();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const filenames = pdfToolsFiles.map(file => file.filename);
|
// Include rotation data for each file
|
||||||
|
const filesWithRotation = pdfToolsFiles.map(file => ({
|
||||||
|
filename: file.filename,
|
||||||
|
rotation: file.rotation || 0,
|
||||||
|
original_name: file.original_name
|
||||||
|
}));
|
||||||
|
|
||||||
const response = await makeRequest('/api/merge-pdfs', {
|
const response = await makeRequest('/api/merge-pdfs', {
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
body: JSON.stringify({ filenames })
|
body: JSON.stringify({ files: filesWithRotation })
|
||||||
});
|
});
|
||||||
|
|
||||||
if (response.success) {
|
if (response.success) {
|
||||||
@@ -283,9 +424,30 @@ function displaySplitFile() {
|
|||||||
document.getElementById('split-file-details').textContent =
|
document.getElementById('split-file-details').textContent =
|
||||||
`${currentPdfFile.page_count} Seiten • ${formatFileSize(currentPdfFile.size)}`;
|
`${currentPdfFile.page_count} Seiten • ${formatFileSize(currentPdfFile.size)}`;
|
||||||
|
|
||||||
|
// PDF-Vorschau anzeigen falls verfügbar
|
||||||
|
const previewContainer = document.getElementById('split-preview-container');
|
||||||
|
if (currentPdfFile.preview) {
|
||||||
|
previewContainer.innerHTML = `
|
||||||
|
<img src="/uploads/${currentPdfFile.preview}" class="pdf-preview size-medium"
|
||||||
|
alt="${currentPdfFile.original_name}" onclick="showSplitPdfModal()">
|
||||||
|
`;
|
||||||
|
} else {
|
||||||
|
previewContainer.innerHTML = `
|
||||||
|
<div class="pdf-preview pdf-no-preview size-medium">
|
||||||
|
<i class="fas fa-file-pdf"></i>
|
||||||
|
</div>
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
|
||||||
splitFileInfo.style.display = 'block';
|
splitFileInfo.style.display = 'block';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function showSplitPdfModal() {
|
||||||
|
if (currentPdfFile && currentPdfFile.preview) {
|
||||||
|
showPdfModal(currentPdfFile.preview, currentPdfFile.original_name, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
async function convertPdfToImages() {
|
async function convertPdfToImages() {
|
||||||
if (!currentPdfFile) {
|
if (!currentPdfFile) {
|
||||||
showError('Keine PDF-Datei ausgewählt.');
|
showError('Keine PDF-Datei ausgewählt.');
|
||||||
@@ -339,4 +501,11 @@ function showError(message) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Global functions
|
// Global functions
|
||||||
window.removeMergeFile = removeMergeFile;
|
window.removeMergeFile = removeMergeFile;
|
||||||
|
window.rotatePdf = rotatePdf;
|
||||||
|
window.movePdfUp = movePdfUp;
|
||||||
|
window.movePdfDown = movePdfDown;
|
||||||
|
window.showPdfModal = showPdfModal;
|
||||||
|
window.rotatePdfInModal = rotatePdfInModal;
|
||||||
|
window.updatePdfPreviewSize = updatePdfPreviewSize;
|
||||||
|
window.showSplitPdfModal = showSplitPdfModal;
|
||||||
@@ -99,6 +99,31 @@
|
|||||||
|
|
||||||
<div class="col-lg-4">
|
<div class="col-lg-4">
|
||||||
<div class="card">
|
<div class="card">
|
||||||
|
<div class="card-header">
|
||||||
|
<h6 class="mb-0">
|
||||||
|
<i class="fas fa-cog me-2"></i>Einstellungen
|
||||||
|
</h6>
|
||||||
|
</div>
|
||||||
|
<div class="card-body">
|
||||||
|
<div class="mb-3">
|
||||||
|
<label class="form-label">Vorschau-Größe:</label>
|
||||||
|
<select id="pdf-preview-size" class="form-select" onchange="updatePdfPreviewSize()">
|
||||||
|
<option value="small">Klein (80px)</option>
|
||||||
|
<option value="medium" selected>Mittel (120px)</option>
|
||||||
|
<option value="large">Groß (160px)</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="form-check mb-3">
|
||||||
|
<input class="form-check-input" type="checkbox" id="show-pdf-info" checked>
|
||||||
|
<label class="form-check-label">
|
||||||
|
PDF-Informationen anzeigen
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="card mt-3">
|
||||||
<div class="card-header">
|
<div class="card-header">
|
||||||
<h6 class="mb-0">
|
<h6 class="mb-0">
|
||||||
<i class="fas fa-info-circle me-2"></i>Anleitung
|
<i class="fas fa-info-circle me-2"></i>Anleitung
|
||||||
@@ -108,9 +133,17 @@
|
|||||||
<ol class="mb-0">
|
<ol class="mb-0">
|
||||||
<li class="mb-2">Wählen Sie mindestens 2 PDF-Dateien aus</li>
|
<li class="mb-2">Wählen Sie mindestens 2 PDF-Dateien aus</li>
|
||||||
<li class="mb-2">Sortieren Sie die Reihenfolge durch Ziehen</li>
|
<li class="mb-2">Sortieren Sie die Reihenfolge durch Ziehen</li>
|
||||||
|
<li class="mb-2">Rotieren Sie PDFs bei Bedarf</li>
|
||||||
<li class="mb-2">Klicken Sie auf "PDFs zusammenführen"</li>
|
<li class="mb-2">Klicken Sie auf "PDFs zusammenführen"</li>
|
||||||
<li>Laden Sie die zusammengeführte PDF herunter</li>
|
<li>Laden Sie die zusammengeführte PDF herunter</li>
|
||||||
</ol>
|
</ol>
|
||||||
|
|
||||||
|
<div class="mt-3">
|
||||||
|
<small class="text-muted">
|
||||||
|
<i class="fas fa-lightbulb me-1"></i>
|
||||||
|
<strong>Tipp:</strong> Klicken Sie auf eine PDF-Vorschau für eine größere Ansicht der ersten Seite.
|
||||||
|
</small>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -142,7 +175,9 @@
|
|||||||
<div class="card bg-light">
|
<div class="card bg-light">
|
||||||
<div class="card-body">
|
<div class="card-body">
|
||||||
<div class="d-flex align-items-center">
|
<div class="d-flex align-items-center">
|
||||||
<i class="fas fa-file-pdf fa-2x text-danger me-3"></i>
|
<div id="split-preview-container" class="me-3">
|
||||||
|
<i class="fas fa-file-pdf fa-2x text-danger"></i>
|
||||||
|
</div>
|
||||||
<div class="flex-grow-1">
|
<div class="flex-grow-1">
|
||||||
<h6 id="split-filename" class="mb-1"></h6>
|
<h6 id="split-filename" class="mb-1"></h6>
|
||||||
<small id="split-file-details" class="text-muted"></small>
|
<small id="split-file-details" class="text-muted"></small>
|
||||||
|
|||||||
@@ -1,2 +0,0 @@
|
|||||||
# Diese Datei sorgt dafür, dass der uploads Ordner in Git erhalten bleibt
|
|
||||||
# Der Ordnerinhalt wird durch .gitignore ignoriert
|
|
||||||
Reference in New Issue
Block a user