Apex · APEX Css · APEX image · HTML · javascript · PDF

Métodos para Convertir HTML a PDF en Oracle APEX

Convertir contenido HTML a PDF es un requisito común en aplicaciones web. Este artículo de blog demuestra tres enfoques diferentes para lograr esto en aplicaciones Oracle APEX, cada uno con sus propias ventajas y casos de uso.

🔗 Demo

RESUMEN DE MÉTODOS

  • Método 1: jsPDF con Dimensiones Fijas – Generación de PDF simple y predecible con tamaños de página predefinidos
  • Método 2: jsPDF con Escalado Dinámico – Adaptación inteligente del contenido con orientación y escalado automático
  • Método 3: Método de Impresión del Navegador – Aprovecha las capacidades nativas de generación de PDF del navegador

CONFIGURACIÓN DE BASE DE DATOS

Primero, crea la tabla para almacenar documentos HTML. Para el script DDL completo, consulta html_tmp_table.sql

LIBRERÍAS REQUERIDAS

Agrega estas librerías a tu página APEX (Página > JavaScript > File URLs):

https://github.com/Aftorres02/blog_app_examples/tree/master/post_2025/18_tmp_html_to_pdf_dow/libs

Referencias de Librerías:

PROCESO APEX

Crea un proceso AJAX llamado GET_HTML_CONTENT:

declare
    l_html_content clob;
    l_document_id number;
begin
    l_document_id := apex_application.g_x01;
    
    select html_content, document_name
    into l_html_content, :P1210_DOCUMENT_NAME
    from html_documents
    where id = l_document_id
    and active_yn = 'Y';
    
    apex_json.open_object;
    apex_json.write('html_content', l_html_content);
    apex_json.write('document_name', :P1210_DOCUMENT_NAME);
    apex_json.close_object;
    
exception
    when no_data_found then
        apex_json.open_object;
        apex_json.write('error', 'Document not found');
        apex_json.close_object;
end;

MÉTODO 1: jsPDF con Dimensiones Fijas

Qué hace: Crea un PDF con dimensiones predefinidas (900×630 puntos) y convierte el contenido HTML directamente al formato PDF. Este método proporciona buen control sobre el tamaño de página, pero puede no ajustarse automáticamente a las dimensiones del contenido.

apex.server.process(
  "GET_HTML_CONTENT",
  {
    x01: apex.item("P1210_DOCUMENT_ID").getValue(),
  },
  {
    success: function (data) {
      var doc = new jspdf.jsPDF("p", "pt", [900, 630]);

      doc.html(data.html_content, {
        callback: function (doc) {
          if (doc.getNumberOfPages() >= 2) {
            doc.deletePage(2);
          }
          var filename = data.document_name;
          doc.save(filename + ".pdf");
        },

        // Establecer el punto de inicio de renderizado y tamaño
        x: 0,
        y: 0,
        margin: 20,
        width: 590, // ANCHO completo de la página en puntos
        windowWidth: 590, // Opcional: ayuda a html2canvas a entender el layout

        html2canvas: {
          useCORS: true,
          allowTaint: true,
          scale: 1, // Ajustar esto para calidad vs rendimiento
        },
      });
    },
    error: function () {
      alert("Error loading document content");
    },
  }
);

MÉTODO 2: jsPDF con Orientación y Escalado Dinámico

Qué hace: Detecta automáticamente las dimensiones del contenido y elige la mejor orientación (vertical/horizontal) y factor de escalado para ajustar el contenido perfectamente dentro de la página PDF. Este método proporciona la adaptación de contenido más inteligente.

apex.server.process(
  "GET_HTML_CONTENT",
  {
    x01: apex.item("P1210_DOCUMENT_ID").getValue(),
  },
  {
    success: function (data) {
      // Crear un contenedor oculto dinámicamente
      let tempContainer = document.createElement("div");
      tempContainer.id = "htmlContentHidden";
      document.body.appendChild(tempContainer);

      // Insertar contenido HTML
      tempContainer.innerHTML = data.html_content;

      // Medir dimensiones del contenido
      const contentWidth = tempContainer.scrollWidth;
      const contentHeight = tempContainer.scrollHeight;

      // Decidir orientación basada en la proporción de aspecto
      let orientation = contentWidth > contentHeight ? "l" : "p";

      // Inicializar jsPDF con orientación dinámica
      const { jsPDF } = window.jspdf;
      let doc = new jsPDF(orientation, "pt", "a4");

      // Obtener dimensiones reales de página de jsPDF
      const pageWidth = doc.internal.pageSize.getWidth();
      const pageHeight = doc.internal.pageSize.getHeight();

      // Calcular escala para que el contenido se ajuste al ancho de página (máx = 1)
      const scaleFactor = Math.min((pageWidth - 40) / contentWidth, 1);

      // Generar PDF
      doc.html(tempContainer, {
        callback: function (doc) {
          doc.save("dynamic_fit.pdf");
          // Limpiar
          document.body.removeChild(tempContainer);
        },
        x: 20,
        y: 20,
        width: pageWidth - 40, // ancho utilizable con márgenes
        windowWidth: contentWidth, // ancho HTML original
        html2canvas: {
          scale: scaleFactor,
          useCORS: true,
          allowTaint: true,
        },
      });
    },
    error: function () {
      alert("Error loading document content");
    },
  }
);

MÉTODO 3: Método de Impresión del Navegador

Qué hace: Abre el contenido HTML en una nueva ventana del navegador y activa el diálogo de impresión nativo del navegador, permitiendo a los usuarios guardar como PDF usando la funcionalidad PDF integrada de su navegador. Este método aprovecha las capacidades nativas de generación de PDF del navegador.

apex.server.process(
  "GET_HTML_CONTENT",
  {
    x01: apex.item("P1210_DOCUMENT_ID").getValue(),
  },
  {
    success: function (data) {
      var printWindow = window.open('', '_blank', 'width=800,height=600');
      printWindow.document.write('<!DOCTYPE html>');
      printWindow.document.write('<html><head><title>Document</title>');
      printWindow.document.write('<style>body{font-family:Arial,sans-serif;margin:20px;}</style>');
      printWindow.document.write('</head><body>');
      printWindow.document.write(data.html_content);
      printWindow.document.write('</body></html>');
      printWindow.document.close();
      
      setTimeout(function() {
          printWindow.print();
          setTimeout(function() {
              printWindow.close();
          }, 1000);
      }, 500);
    },
    error: function () {
      alert("Error loading document content");
    },
  }
);

Leave a comment