Reducir tamaño de PDF con Telegram

Comprimir PDF con Bot de Telegram

Comprimir un PDF con Telegram es posible gracias a los Bots. Anteriormente en mi blog te contaba cómo comprimir un PDF con Python usando la línea de comandos, PIL y pypdfium2.

Ahora he conectado la compresión de PDF con un Bot de Telegram para que puedas reducir el tamaño de cualquier PDF usando este Bot de Telegram de manera gratis, además de que el código fuente del Bot es Open source.

Bot de Telegram - Comprimir PDF (reducir tamaño)
Bot de Telegram – Comprimir PDF (reducir tamaño)

Veamos cómo funciona este Bot de Telegram para comprimir un PDF reduciendo su tamaño. Cuando le envíes un documento PDF al Bot de Telegram puedes especificar la escala de extracción de imagen así como la calidad resultante, siendo capaz de comprimir el PDF encontrando un equilibrio entre calidad y tamaño.

Funcionamiento de compresión

Como ya lo expliqué en el post que contiene el código Python, para reducir el tamaño de un PDF con el Bot de Telegram lo que se hace es convertir cada página del documento a una imagen (como si le tomaras capturas de pantalla, pero manteniendo la calidad), comprimir esa imagen y luego unir cada imagen en un PDF ya comprimido.

Estoy explicando el funcionamiento ya que a partir de esto el tamaño del PDF reducido puede variar. No pesa lo mismo un PDF con varias ilustraciones que uno de puro texto, pero según mis pruebas siempre se reduce el tamaño cuando otros compresores no lo han hecho.

Método de Python para comprimir PDF

He encerrado la reducción del tamaño de PDF en la siguiente función de Python. Más adelante esa función será invocada desde Telegram, o mejor dicho, cuando se reciba una actualización del Bot de Telegram al hacer polling:

def comprimir_pdf(nombre_pdf, escala: int = 2, calidad: int = 70):
    nombre_pdf_comprimido = uuid.uuid4().hex + ".pdf"
    nombre_pdf_sin_extension = Path(nombre_pdf).stem
    """
    Extraer cada página del PDF como imagen
    """
    pdf = pdfium.PdfDocument(nombre_pdf)
    cantidad_paginas = len(pdf)
    imagenes = []
    for indice_pagina in range(cantidad_paginas):
        numero_pagina = indice_pagina+1
        nombre_imagen = f"{nombre_pdf_sin_extension}_{numero_pagina}.jpg"
        imagenes.append(nombre_imagen)
        pagina = pdf.get_page(indice_pagina)
        imagen_para_pil = pagina.render(scale=escala).to_pil()
        imagen_para_pil.save(nombre_imagen)

    imagenes_comprimidas = []
    """
    Comprimir imágenes.
    Entre menor calidad, menos peso del PDF resultante
    """
    for nombre_imagen in imagenes:
        nombre_imagen_sin_extension = Path(nombre_imagen).stem
        nombre_imagen_salida = nombre_imagen_sin_extension + \
            "_comprimida" + nombre_imagen[nombre_imagen.rfind("."):]
        imagen = Image.open(nombre_imagen)
        """
        El parámetro quality para JPEG se especifica en:
        https://pillow-wiredfool.readthedocs.io/en/latest/handbook/image-file-formats.html#jpeg
        """
        imagen.save(nombre_imagen_salida, optimize=True, quality=calidad)
        imagenes_comprimidas.append(nombre_imagen_salida)

    """
    Escribir imágenes en un nuevo PDF
    """
    with open(nombre_pdf_comprimido, "wb") as documento:
        documento.write(img2pdf.convert(imagenes_comprimidas))

    """
    Eliminar imágenes temporales
    """
    for imagen in imagenes + imagenes_comprimidas:
        os.remove(imagen)
    pdf.close()
    return nombre_pdf_comprimido

Esta función recibe el nombre del PDF que se va a comprimir (o mejor dicho, su ubicación), la escala para extraer las imágenes y la calidad a la que se va a reducir cada página. Devuelve la ubicación del PDF ya comprimido.

Bot de Telegram para comprimir PDF

Reducir tamaño de PDF con Telegram
Reducir tamaño de PDF con Telegram

Ahora solo hay que escuchar las actualizaciones para ver si un usuario ha enviado un mensaje o un documento PDF al Bot:

async def manejadorDeActualizaciones(update: Update, context: ContextTypes.DEFAULT_TYPE) -> None:
    if update.message == None:
        return
    if update.message.text =="/start":
        await update.message.reply_text(MENSAJE_AYUDA)
    if update.message.document != None:
        if update.message.document.mime_type != "application/pdf":
            return
        escala = ESCALA_POR_DEFECTO
        calidad = CALIDAD_POR_DEFECTO
        if update.message.caption != None:
            escala, calidad = parsear_escala_y_calidad(
                update.message.caption)
        await update.message.reply_text(f"Extrayendo páginas con escala {escala} y reduciendo calidad al {calidad} %.\n"+MENSAJE_AYUDA+"\nComprimiendo PDF...")
        archivo_recibido_desde_telegram = await update.message.effective_attachment.get_file()
        nombre_aleatorio_pdf_recibido = uuid.uuid4().hex
        ubicacion_archivo_recibido = await archivo_recibido_desde_telegram.download_to_drive(nombre_aleatorio_pdf_recibido + ".pdf")
        ubicacion_pdf_comprimido = comprimir_pdf(
            ubicacion_archivo_recibido, escala, calidad)
        await update.message.chat.send_document(ubicacion_pdf_comprimido, "Aquí tienes tu PDF comprimido según los parámetros indicados")
        os.remove(ubicacion_archivo_recibido)
        os.remove(ubicacion_pdf_comprimido)

Por ahora solo estoy manejando dos opciones: cuando el usuario envía el comando /start para mostrarle la ayuda, y cuando el usuario envía un documento.

Cuando el usuario envía un documento al Bot de Telegram compruebo que su tipo sea application/pdf, reviso si tiene una descripción (ya que se puede especificar la escala y calidad en el caption del documento), calculo un nombre único y aleatorio con uuid4, después lo descargo de la nube de Telegram con download_to_drive, invoco a la función que reduce el tamaño del PDF y envío el PDF comprimido con send_document.

Finalmente elimino el PDF que descargué (el que estaba sin comprimir) así como el PDF ya comprimido que envié a Telegram como respuesta a la solicitud del usuario de reducir el peso de su PDF.

Poniendo todo junto

El código fuente completo del Bot así como sus dependencias de Python se encuentran en el siguiente repositorio de GitHub: https://github.com/parzibyte/pdf_compress_telegram_bot

Puedes alojar este Bot en cualquier lugar, incluso en tu equipo local siempre y cuando tengas conexión a internet. Así cualquier usuario será capaz de enviar documentos PDF al Bot y comprimirlos.

Estoy aquí para ayudarte 🤝💻


Estoy aquí para ayudarte en todo lo que necesites. Si requieres alguna modificación en lo presentado en este post, deseas asistencia con tu tarea, proyecto o precisas desarrollar un software a medida, no dudes en contactarme. Estoy comprometido a brindarte el apoyo necesario para que logres tus objetivos. Mi correo es parzibyte(arroba)gmail.com, estoy como@parzibyte en Telegram o en mi página de contacto

No te pierdas ninguno de mis posts 🚀🔔

Suscríbete a mi canal de Telegram para recibir una notificación cuando escriba un nuevo tutorial de programación.

Dejar un comentario

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *