import os import io from flask import Flask, render_template, request, send_file, Response from PIL import Image from PyPDF2 import PdfMerger app = Flask(__name__) @app.route('/') def index(): return render_template('index.html') # Función para manejar la subida y la combinación de archivos @app.route('/combine', methods=['POST']) def combine_files(): if 'files' not in request.files: return Response('No se seleccionaron archivos', status=400) uploaded_files = request.files.getlist('files') if not uploaded_files: return Response('No se seleccionaron archivos', status=400) # NUEVO: Obtener el nivel de compresión (0 a 100) del formulario compression_level_str = request.form.get('compression_level', '85') try: # Convertir a entero. Usamos 85 como calidad estándar si falla. compression_level = int(compression_level_str) if not 0 <= compression_level <= 100: compression_level = 85 except ValueError: compression_level = 85 pdf_merger = PdfMerger() image_pdfs = [] # 1. Ajuste de calidad para la compresión JPEG # Para archivos PDF generados a partir de imágenes, la calidad afecta la compresión JPEG interna. # 95 es alta calidad, 50 es compresión media. quality = compression_level try: for file in uploaded_files: file_name = file.filename.lower() file_stream = io.BytesIO(file.read()) if file_name.endswith(('.pdf')): # Si es PDF, se agrega directamente SIN COMPRESIÓN. pdf_merger.append(file_stream) elif file_name.endswith(('.jpg', '.jpeg', '.png')): # Si es una imagen, la convertimos a PDF con compresión. try: img = Image.open(file_stream) if img.mode != 'RGB': img = img.convert('RGB') pdf_stream = io.BytesIO() # APLICACIÓN DE COMPRESIÓN AL CONVERTIR LA IMAGEN A PDF # El argumento 'quality' controla el nivel de compresión JPEG interna del PDF. img.save( pdf_stream, format='PDF', quality=quality, resolution=100.0 # Resolución estándar para pantalla ) pdf_stream.seek(0) pdf_merger.append(pdf_stream) image_pdfs.append(pdf_stream) except Exception as e: return Response(f"Error al procesar la imagen {file_name}: {e}", status=500) # Ignorar otros tipos de archivo else: print(f"Archivo ignorado: {file_name}") final_pdf_stream = io.BytesIO() pdf_merger.write(final_pdf_stream) pdf_merger.close() final_pdf_stream.seek(0) return send_file( final_pdf_stream, as_attachment=True, download_name=request.form.get('filename', 'documento_combinado.pdf'), mimetype='application/pdf' ) except Exception as e: print(f"Error general: {e}") return Response(f'Ocurrió un error inesperado en el servidor: {e}', status=500) finally: for pdf_stream in image_pdfs: pdf_stream.close() if __name__ == '__main__': # Obtener el puerto de las variables de entorno, usando 7860 como fallback port = int(os.environ.get('PORT', 7860)) # Ejecutar la aplicación en el host 0.0.0.0 para que sea accesible externamente app.run(host='0.0.0.0', port=port, debug=False)