pdf-to-word / index.html
fernandox's picture
Add 2 files
77aaeaa verified
<!DOCTYPE html>
<html lang="es">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>PDF a Word - Conversor Offline</title>
<!-- Bootstrap CSS -->
<link href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css" rel="stylesheet">
<!-- Font Awesome para iconos -->
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
<style>
:root {
--primary-color: #4e73df;
--secondary-color: #f8f9fc;
--accent-color: #2e59d9;
--text-color: #5a5c69;
}
body {
font-family: 'Nunito', sans-serif;
background-color: #f8f9fc;
color: var(--text-color);
}
.card {
border-radius: 15px;
box-shadow: 0 0.15rem 1.75rem 0 rgba(58, 59, 69, 0.15);
border: none;
}
.card-header {
background-color: var(--primary-color);
color: white;
border-radius: 15px 15px 0 0 !important;
font-weight: 600;
}
.btn-primary {
background-color: var(--primary-color);
border-color: var(--primary-color);
}
.btn-primary:hover {
background-color: var(--accent-color);
border-color: var(--accent-color);
}
.dropzone {
border: 2px dashed #d1d3e2;
border-radius: 10px;
padding: 2rem;
text-align: center;
cursor: pointer;
transition: all 0.3s;
background-color: white;
}
.dropzone:hover {
border-color: var(--primary-color);
background-color: var(--secondary-color);
}
.dropzone.active {
border-color: var(--primary-color);
background-color: var(--secondary-color);
}
.file-info {
background-color: white;
border-radius: 8px;
padding: 15px;
margin-top: 15px;
display: none;
}
.progress {
height: 10px;
margin-top: 10px;
}
.conversion-result {
display: none;
}
.file-icon {
font-size: 3rem;
color: var(--primary-color);
}
.file-size-warning {
color: #e74a3b;
font-weight: 600;
display: none;
}
.conversion-time {
font-size: 0.9rem;
color: #858796;
}
</style>
</head>
<body>
<div class="container py-5">
<div class="row justify-content-center">
<div class="col-lg-8">
<div class="card shadow-lg">
<div class="card-header py-3 d-flex justify-content-between align-items-center">
<h4 class="m-0 font-weight-bold"><i class="fas fa-file-word me-2"></i> Conversor PDF a Word</h4>
<span class="badge bg-light text-dark">Offline</span>
</div>
<div class="card-body">
<p class="text-muted mb-4">Convierte tus archivos PDF a documentos Word (.docx) directamente en tu navegador. Tus archivos nunca salen de tu computadora.</p>
<div id="dropzone" class="dropzone">
<i class="fas fa-file-pdf file-icon mb-3"></i>
<h5>Arrastra y suelta tu archivo PDF aqu铆</h5>
<p class="text-muted">o haz clic para seleccionar</p>
<input type="file" id="fileInput" class="d-none" accept=".pdf">
<button class="btn btn-primary mt-3">
<i class="fas fa-folder-open me-2"></i> Seleccionar archivo
</button>
<p class="file-size-warning mt-2">
<i class="fas fa-exclamation-triangle me-2"></i>
El archivo no debe superar los 50MB
</p>
</div>
<div id="fileInfo" class="file-info">
<div class="d-flex justify-content-between align-items-center">
<div>
<h6 id="fileName" class="mb-0"></h6>
<small class="text-muted" id="fileSize"></small>
</div>
<button id="removeFile" class="btn btn-sm btn-outline-danger">
<i class="fas fa-times"></i>
</button>
</div>
</div>
<div class="mt-4">
<div class="d-flex justify-content-between mb-2">
<label for="quality" class="form-label">Opciones de conversi贸n:</label>
<span class="badge bg-info">Texto editable</span>
</div>
<select class="form-select mb-3" id="conversionType">
<option value="text">Mantener texto editable</option>
<option value="image">Convertir como imagen (mantiene formato)</option>
</select>
<button id="convertBtn" class="btn btn-primary w-100 py-2" disabled>
<i class="fas fa-exchange-alt me-2"></i> Convertir a Word
</button>
<div class="progress mt-3 d-none" id="progressBar">
<div class="progress-bar progress-bar-striped progress-bar-animated" role="progressbar" style="width: 0%"></div>
</div>
</div>
<div id="conversionResult" class="conversion-result mt-4 text-center">
<div class="alert alert-success">
<i class="fas fa-check-circle me-2"></i>
<span id="successMessage">Conversi贸n completada con 茅xito!</span>
<p class="conversion-time mb-0" id="conversionTime"></p>
</div>
<button id="downloadBtn" class="btn btn-success mt-2">
<i class="fas fa-download me-2"></i> Descargar archivo Word
</button>
</div>
</div>
<div class="card-footer text-muted text-center">
<small>Procesamiento 100% en tu navegador 路 L铆mite de 50MB 路 No se suben archivos a servidores</small>
</div>
</div>
</div>
</div>
</div>
<!-- Bootstrap JS Bundle with Popper -->
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/js/bootstrap.bundle.min.js"></script>
<!-- PDF-lib para manejar PDFs -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/pdf-lib/1.17.1/pdf-lib.min.js"></script>
<!-- Docx para generar documentos Word -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/docx/7.1.0/docx.min.js"></script>
<!-- FileSaver para descargar el archivo -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/FileSaver.js/2.0.5/FileSaver.min.js"></script>
<script>
document.addEventListener('DOMContentLoaded', function() {
// Elementos del DOM
const dropzone = document.getElementById('dropzone');
const fileInput = document.getElementById('fileInput');
const fileInfo = document.getElementById('fileInfo');
const fileName = document.getElementById('fileName');
const fileSize = document.getElementById('fileSize');
const removeFile = document.getElementById('removeFile');
const convertBtn = document.getElementById('convertBtn');
const progressBar = document.getElementById('progressBar');
const conversionResult = document.getElementById('conversionResult');
const downloadBtn = document.getElementById('downloadBtn');
const successMessage = document.getElementById('successMessage');
const conversionTime = document.getElementById('conversionTime');
const fileSizeWarning = document.querySelector('.file-size-warning');
const conversionType = document.getElementById('conversionType');
let selectedFile = null;
let convertedDoc = null;
// Eventos para el dropzone
dropzone.addEventListener('click', () => fileInput.click());
fileInput.addEventListener('change', handleFileSelect);
['dragenter', 'dragover', 'dragleave', 'drop'].forEach(eventName => {
dropzone.addEventListener(eventName, preventDefaults, false);
});
function preventDefaults(e) {
e.preventDefault();
e.stopPropagation();
}
['dragenter', 'dragover'].forEach(eventName => {
dropzone.addEventListener(eventName, highlight, false);
});
['dragleave', 'drop'].forEach(eventName => {
dropzone.addEventListener(eventName, unhighlight, false);
});
function highlight() {
dropzone.classList.add('active');
}
function unhighlight() {
dropzone.classList.remove('active');
}
dropzone.addEventListener('drop', handleDrop, false);
function handleDrop(e) {
const dt = e.dataTransfer;
const file = dt.files[0];
handleFile(file);
}
function handleFileSelect(e) {
const file = e.target.files[0];
handleFile(file);
}
function handleFile(file) {
if (!file) return;
// Verificar tipo de archivo
if (file.type !== 'application/pdf') {
showAlert('Por favor, selecciona un archivo PDF v谩lido.', 'danger');
return;
}
// Verificar tama帽o del archivo (50MB m谩ximo)
if (file.size > 50 * 1024 * 1024) {
fileSizeWarning.style.display = 'block';
convertBtn.disabled = true;
return;
} else {
fileSizeWarning.style.display = 'none';
}
selectedFile = file;
// Mostrar informaci贸n del archivo
fileName.textContent = file.name;
fileSize.textContent = formatFileSize(file.size);
fileInfo.style.display = 'block';
convertBtn.disabled = false;
// Ocultar resultado de conversi贸n previa
conversionResult.style.display = 'none';
}
removeFile.addEventListener('click', function() {
selectedFile = null;
fileInput.value = '';
fileInfo.style.display = 'none';
convertBtn.disabled = true;
conversionResult.style.display = 'none';
});
// Formatear tama帽o de archivo
function formatFileSize(bytes) {
if (bytes === 0) return '0 Bytes';
const k = 1024;
const sizes = ['Bytes', 'KB', 'MB', 'GB'];
const i = Math.floor(Math.log(bytes) / Math.log(k));
return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + ' ' + sizes[i];
}
// Convertir PDF a Word
convertBtn.addEventListener('click', async function() {
if (!selectedFile) return;
try {
// Mostrar barra de progreso
progressBar.classList.remove('d-none');
const progressBarInner = progressBar.querySelector('.progress-bar');
progressBarInner.style.width = '0%';
convertBtn.disabled = true;
// Simular progreso (en una implementaci贸n real esto ser铆a el progreso real)
let progress = 0;
const progressInterval = setInterval(() => {
progress += 5;
progressBarInner.style.width = `${progress}%`;
if (progress >= 100) {
clearInterval(progressInterval);
}
}, 200);
// Leer el archivo PDF
const arrayBuffer = await readFileAsArrayBuffer(selectedFile);
// Registrar tiempo de inicio
const startTime = new Date();
// Convertir PDF a Word (simulaci贸n)
// NOTA: En un entorno real usar铆as pdf-lib y docx para la conversi贸n
// Esta es una simulaci贸n porque la conversi贸n real requiere m谩s c贸digo
await simulateConversion();
// Registrar tiempo de finalizaci贸n
const endTime = new Date();
const conversionDuration = ((endTime - startTime) / 1000).toFixed(2);
// Mostrar resultado
progressBarInner.style.width = '100%';
setTimeout(() => {
progressBar.classList.add('d-none');
// Mostrar resultado exitoso
successMessage.textContent = 'Conversi贸n completada con 茅xito!';
conversionTime.textContent = `Tiempo de conversi贸n: ${conversionDuration} segundos`;
conversionResult.style.display = 'block';
convertBtn.disabled = false;
}, 500);
} catch (error) {
console.error('Error durante la conversi贸n:', error);
showAlert('Ocurri贸 un error durante la conversi贸n. Por favor, intenta nuevamente.', 'danger');
progressBar.classList.add('d-none');
convertBtn.disabled = false;
}
});
// Descargar archivo convertido
downloadBtn.addEventListener('click', function() {
if (!convertedDoc) return;
// En una implementaci贸n real, usar铆as el docx generado
// Aqu铆 simulamos la descarga del archivo
const blob = new Blob(["Este ser铆a el contenido del archivo Word generado"], {type: "application/vnd.openxmlformats-officedocument.wordprocessingml.document"});
const fileNameWithoutExt = selectedFile.name.replace('.pdf', '');
saveAs(blob, `${fileNameWithoutExt}.docx`);
showAlert('Descarga iniciada!', 'success');
});
// Funciones auxiliares
function readFileAsArrayBuffer(file) {
return new Promise((resolve, reject) => {
const reader = new FileReader();
reader.onload = () => resolve(reader.result);
reader.onerror = reject;
reader.readAsArrayBuffer(file);
});
}
function simulateConversion() {
return new Promise(resolve => {
setTimeout(resolve, 3000); // Simula una conversi贸n de 3 segundos
});
}
function showAlert(message, type) {
const alertDiv = document.createElement('div');
alertDiv.className = `alert alert-${type} alert-dismissible fade show mt-3`;
alertDiv.innerHTML = `
${message}
<button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Close"></button>
`;
const container = document.querySelector('.card-body');
container.insertBefore(alertDiv, container.firstChild);
// Eliminar la alerta despu茅s de 5 segundos
setTimeout(() => {
const bsAlert = new bootstrap.Alert(alertDiv);
bsAlert.close();
}, 5000);
}
});
</script>
<p style="border-radius: 8px; text-align: center; font-size: 12px; color: #fff; margin-top: 16px;position: fixed; left: 8px; bottom: 8px; z-index: 10; background: rgba(0, 0, 0, 0.8); padding: 4px 8px;">Made with <img src="https://enzostvs-deepsite.hf.space/logo.svg" alt="DeepSite Logo" style="width: 16px; height: 16px; vertical-align: middle;display:inline-block;margin-right:3px;filter:brightness(0) invert(1);"><a href="https://enzostvs-deepsite.hf.space" style="color: #fff;text-decoration: underline;" target="_blank" >DeepSite</a> - 馃К <a href="https://enzostvs-deepsite.hf.space?remix=fernandox/pdf-to-word" style="color: #fff;text-decoration: underline;" target="_blank" >Remix</a></p></body>
</html>