Control de disputas sobre archivos PDF con Adobe PDF Embed API | Programar Plus

Según nuestra última estimación, ahora hay más archivos PDF en el mundo que átomos en el universo (no verificados por fuentes externas), por lo que es probable que, de vez en cuando, te encuentres con uno o dos documentos PDF. Los navegadores hacen un trabajo razonablemente bueno al manejar archivos PDF. Por lo general, al hacer clic en un enlace a un PDF, se abrirá una nueva pestaña en su navegador con una interfaz de usuario personalizada y una representación por navegador. Aquí está el mismo PDF abierto en Edge, Chrome, Firefox y Safari, respectivamente:

Como era de esperar, cada navegador le da su propio giro a las cosas, pero una cosa es consistente: todos ellos toman el control de toda la ventana gráfica para representar el PDF. Si bien esto es útil para darle al lector la mayor cantidad de espacio posible para consumir el PDF, a veces sería deseable tener más control sobre la experiencia PDF. Aquí es donde entra en juego la API de Adobe PDF Embed. La API de PDF Embed es una biblioteca de JavaScript gratuita que le permite mostrar archivos PDF en línea con el resto de su contenido, además de brindarle control sobre la interfaz de usuario de las herramientas, admitir anotaciones y eventos, y más. Veamos algunos ejemplos de cómo es trabajar con la biblioteca.

conseguir una llave

Antes de comenzar, deberá registrarse para obtener una clave. Si se dirige a nuestra página de Introducción, verá un enlace que le permitirá crear nuevas credenciales:

Si aún no tiene una cuenta con Adobe, deberá crear una. Se le pedirá que asigne a las credenciales un nombre y un dominio de aplicación. Si bien el nombre no es muy importante, el dominio de la aplicación sí lo es. La clave que obtenga estará restringida a un dominio en particular. Solo puede ingresar un dominio aquí, así que para comenzar, puede usar localhost o usar cdpn.io como dominio si desea probarlo en CodePen. Si desea utilizar la API tanto en entornos locales como de producción, puede crear varios proyectos en la consola o utilizar configuraciones de archivos HOSTS. (La capacidad de especificar múltiples dominios para las credenciales está en el radar).

Presiona el encantador botón azul “Crear credenciales” y obtendrás tu clave:

Si tiene curiosidad y desea ver qué puede hacer la API integrada de inmediato, haga clic en “Obtener muestras de código”, que lo lleva a una demostración interactiva en línea. Pero dado que somos programadores incondicionales que construimos nuestros propios editores antes de ir a trabajar, profundicemos en un ejemplo simple.

Creación de una demostración

Primero, construyamos una página HTML que aloje nuestro PDF. He sido desarrollador web durante veinte años y ahora soy un experto en el diseño de hermosas páginas HTML. Esto es lo que se me ocurrió:

<html>
  <head></head>
  <body>
    <h1>Cats are Everything</h1>
    <p>
      Cats are so incredibly awesome that I feel like
      we should talk about them more. Here's a PDF
      that talks about how awesome cats are.
    </p>
		
    <!-- PDF here! -->

    <p>
      Did you like that? Was it awesome? I think it was awesome! 
    </p>
  </body>
</html>

Lo puse un poco de CSS, por supuesto:

Un encabezado que dice Cats are Everything, seguido de dos breves párrafos sobre gatos.  El texto es blanco sobre un fondo verde.

Honestamente, no sé por qué Adobe me contrató como desarrollador evangelista porque, claramente, debería estar en un equipo de diseño. De todos modos, ¿cómo conseguimos nuestro PDF allí? El primer paso es agregar nuestra biblioteca SDK:

<script src="https://documentcloud.adobe.com/view-sdk/main.js"></script>

Ahora necesitamos un poco de JavaScript. Cuando nuestra biblioteca se carga, dispara un evento llamado adobe_dc_view_sdk.ready. Dependiendo de cómo cargue sus scripts y el marco de su elección, es posible que el evento se active antes de que tenga la oportunidad de verificarlo.

También podemos comprobar la existencia de window.AdobeDC. Podemos manejar ambos encadenándolos a una función que configurará nuestro PDF.

if (window.AdobeDC) displayPDF();
else {
  document.addEventListener("adobe_dc_view_sdk.ready", () => displayPDF());
}

function displayPDF() {
  console.log('Lets do some AWESOME PDF stuff!');
}

Muy bien, entonces, ¿cómo mostramos el PDF? Para aceptar todos los valores predeterminados, podemos usar el siguiente fragmento:

let adobeDCView = new AdobeDC.View({clientId: ADOBE_KEY, divId: "mypdf" });
adobeDCView.previewFile({
  content:{location: {url: "https://static.raymondcamden.com/enclosures/cat.pdf"}},
  metaData:{fileName: "cat.pdf"}
});

Analicemos eso. Primero, creamos un nuevo AdobeDC.View objeto. El clientId el valor es la clave de antes. El divId es la identificación de un <div> en el DOM donde se renderizará el PDF. Eliminé el comentario HTML que tenía antes y lo dejé en un espacio vacío. <div> con esa identificación. También usé algo de CSS para especificar un ancho y una altura:

#mypdf {
  width: 100%;
  height: 500px;
}

El previewFile El método toma dos argumentos principales. La primera es la URL del PDF. La API de inserción de PDF funciona con URL o promesas de archivos. Para las URL, queremos asegurarnos de que tenemos la configuración de CORS correctamente. El segundo valor son los metadatos sobre el PDF que, en este caso, es el nombre del archivo. Aquí está el resultado:

Aquí hay un CodePen completo del ejemplo, y sí, puede clonarlo, modificarlo y continuar usando la clave.

Notará que la interfaz de usuario contiene las mismas herramientas que esperaría en cualquier visor de PDF, junto con cosas como la capacidad de agregar notas y anotaciones.

Tenga en cuenta el icono “Guardar” en la figura anterior. Cuando se descargue, el PDF incluirá los comentarios y hermosos dibujos con marcadores.

Personalizando la experiencia

Muy bien, has visto el ejemplo básico, así que mejorémoslo un poco y personalicemos la experiencia. Una de las primeras formas en que podemos hacerlo es cambiando el modo de inserción que controla cómo se muestra el PDF. La biblioteca tiene cuatro diferentes compatibles:

  • Contenedor de tamaño —El modo predeterminado utilizado para representar un PDF dentro de un <div> envase. Representa una página a la vez.
  • Ventana completa —Contenedor de tamaño similar en el sentido de que “llenará” su padre <div>, pero muestra todo el PDF en una “secuencia” por la que puede desplazarse.
  • En línea –Lo muestra en una página web, como Contenedor de tamaño, pero representa cada página en una pila vertical. Obviamente, no use esto con un PDF grande de 99 páginas a menos que odie a sus usuarios. (Pero si ya muestra una de esas ventanas modales de “Suscríbase a nuestro boletín” cuando una persona visita su sitio, o si su sitio reproduce videos automáticamente, entonces, por supuesto, continúe y haga esto).
  • Caja ligera –Muestra el PDF en una ventana centrada mientras atenúa el resto del contenido. La interfaz de usuario para cerrar la pantalla se incluye automáticamente.

Para especificar una vista diferente, se puede pasar un segundo argumento de opciones. Por ejemplo:

function displayPDF() {
  console.log('Lets do some AWESOME PDF stuff!');
  let adobeDCView = new AdobeDC.View({clientId: ADOBE_KEY, divId: "mypdf" });
  adobeDCView.previewFile({
    content:{location: {url: "https://static.raymondcamden.com/enclosures/cat.pdf"}},
    metaData:{fileName: "cat.pdf"}
  }, 
  {
    embedMode: "IN_LINE"
  });	
}

Tenga en cuenta que en el modo en línea, la altura especificada para su div se ignorará para que el PDF pueda estirar un poco sus piernas. Puede ver esta versión de la demostración aquí: https://codepen.io/cfjedimaster/pen/OJpJRKr

Consideremos otro ejemplo: el uso de lightbox junto con un botón nos permite darle al usuario la oportunidad de cargar el PDF cuando lo desee. Podemos modificar nuestro HTML así:

<html>
  <head></head>
  <body>
    <h1>Cats are Everything</h1>
    <p>
      Cats are so incredibly awesome that I feel like
      we should talk about them more. Here's a PDF
      that talks about how awesome cats are.
    </p>
		
    <!-- PDF here! -->
    <button id="showPDF" disabled>Show PDF</button>

    <p>
      Did you like that? Was it awesome? I think it was awesome! 
    </p>
  </body>
</html>

Agregué un botón deshabilitado al HTML y eliminé el vacío <div>. No lo necesitaremos ya que el modo de caja de luz usará una vista modal. Ahora modificamos el JavaScript:

const ADOBE_KEY = 'b9151e8d6a0b4d798e0f8d7950efea91';

if(window.AdobeDC) enablePDF();
else {
  document.addEventListener("adobe_dc_view_sdk.ready", () => enablePDF());
}

function enablePDF() {
  let btn = document.querySelector('#showPDF');
  btn.addEventListener('click', () => displayPDF());
  btn.disabled = false;
}

function displayPDF() {
  console.log('Lets do some AWESOME PDF stuff!');
  let adobeDCView = new AdobeDC.View({clientId: ADOBE_KEY });
  adobeDCView.previewFile({
    content:{location: {url: "https://static.raymondcamden.com/enclosures/cat.pdf"}},
    metaData:{fileName: "cat.pdf"}
  }, 
  {
    embedMode: "LIGHT_BOX"
  });	
}

Hay dos cambios principales aquí. En primer lugar, comprobar que la biblioteca se está cargando (o se ha cargado) se ejecuta enablePDF, que elimina la propiedad disabled del botón y agrega un evento de clic. esto corre displayPDF. Observe cómo el inicializador no utiliza el divId nunca más. En segundo lugar, tenga en cuenta la embedMode cambio de modo. Puede intentarlo usted mismo a través del Pen a continuación.

También tiene más opciones de personalización, incluido el ajuste de los menús e íconos de la interfaz de usuario para habilitar y deshabilitar varias funciones:

adobeDCView.previewFile({
	content:{location: {url: "https://static.raymondcamden.com/enclosures/cat.pdf"}},
	metaData:{fileName: "cat.pdf"}
}, 
{
	showDownloadPDF: false,
	showPrintPDF: false,
	showAnnotationTools: false,
	showLeftHandPanel: false
});	

Lo más probable es que puedas adivinar qué hace esto, pero aquí hay una foto con las opciones predeterminadas:

Y así es como se ve con esas opciones deshabilitadas:

Por cierto, solo para que quede claro, definitivamente sabemos que deshabilitar el botón de descarga no “protege” el PDF que se ve aquí, la URL aún está visible a través de Ver código fuente.

Nuevamente, este es solo un pequeño ejemplo, así que asegúrese de consultar los documentos de personalización para obtener más ejemplos.

Trabajar con la API y manejar eventos

Junto con la personalización de la interfaz de usuario, también obtenemos un control detallado sobre la experiencia después de que se carga. Esto es compatible con una API que puede devolver información sobre el PDF, así como la capacidad de escuchar eventos.

Trabajar con la API utiliza el resultado de la previewFile método. Todavía no lo hemos usado, pero devuelve una Promesa. Uno de los usos de la API es obtener metadatos. Aquí hay un ejemplo:

let resultPromise = adobeDCView.previewFile({
  content:{location: {url: "https://static.raymondcamden.com/enclosures/cat.pdf"}},
  metaData:{fileName: "cat.pdf"}
}, { embedMode:"SIZED_CONTAINER" });	

resultPromise.then(adobeViewer => {
  adobeViewer.getAPIs().then(apis => {
    apis.getPDFMetadata()
    .then(result => console.log(result))
    .catch(error => console.log(error));
  });
});

Esto devuelve:

{
  'numPages':6,
  'pdfTitle':'Microsoft Word - Document1',
  'fileName':''
}

Junto con las llamadas a la API, también contamos con una profunda integración de análisis. Si bien los documentos son muy detallados (y hablan sobre la integración con Adobe Analytics), puede manejar la visualización de PDF y los eventos de interacción de cualquier manera que tenga sentido para usted.

Por ejemplo, dado que sabemos cuántas páginas hay en un PDF y podemos escuchar eventos como ver una página, podemos notar cuándo una persona ha visto cada página. Para construir esto, modifiqué el JavaScript, así:

const ADOBE_KEY = 'b9151e8d6a0b4d798e0f8d7950efea91';

//used to track what we've read
const pagesRead = new Set([1]);
let totalPages, adobeDCView, shownAlert=false;

if(window.AdobeDC) displayPDF();
else {
  document.addEventListener("adobe_dc_view_sdk.ready", () => displayPDF());
}

function displayPDF() {
  console.log('Lets do some AWESOME PDF stuff!');
  adobeDCView = new AdobeDC.View({clientId: ADOBE_KEY, divId: "mypdf" });
	
  let resultPromise = adobeDCView.previewFile({
    content:{location: {url: "https://static.raymondcamden.com/enclosures/cat.pdf"}},
    metaData:{fileName: "cat.pdf"}
  }, { embedMode:"SIZED_CONTAINER" });	

  resultPromise.then(adobeViewer => {
    adobeViewer.getAPIs().then(apis => {
      apis.getPDFMetadata()
      .then(result => {
        totalPages = result.numPages;
        console.log('totalPages', totalPages);
        listenForReads();
      })
      .catch(error => console.log(error));
    });
  });
	
}

function listenForReads() {
	
  const eventOptions = {
    enablePDFAnalytics: true
  }

  adobeDCView.registerCallback(
  AdobeDC.View.Enum.CallbackType.EVENT_LISTENER,
  function(event) {
    let page = event.data.pageNumber;
    pagesRead.add(page);
    console.log(`view page ${page}`);
    if(pagesRead.size === totalPages && !shownAlert) {
      alert('You read it all!');
      shownAlert = true;
    }
  }, eventOptions
);

}

Tenga en cuenta que después de obtener información sobre el recuento de páginas, ejecuto una función que comienza a escuchar los eventos de visualización de páginas. Uso un Set para registrar cada página única, y cuando el total es igual al número de páginas en el PDF, alert un mensaje. (Por supuesto, no sabemos si el lector realmente leyó el texto). Si bien es cierto que es un poco tonto, puedes jugar con esto tú mismo aquí:

const ADOBE_KEY = 'b9151e8d6a0b4d798e0f8d7950efea91';

//used to track what we've read
const pagesRead = new Set([1]);
let totalPages, adobeDCView, shownAlert=false;

if(window.AdobeDC) displayPDF();
else {
  document.addEventListener("adobe_dc_view_sdk.ready", () => displayPDF());
}

function displayPDF() {
  console.log('Lets do some AWESOME PDF stuff!');
  adobeDCView = new AdobeDC.View({clientId: ADOBE_KEY, divId: "mypdf" });
	
  let resultPromise = adobeDCView.previewFile({
    content:{location: {url: "https://static.raymondcamden.com/enclosures/cat.pdf"}},
    metaData:{fileName: "cat.pdf"}
  }, { embedMode:"SIZED_CONTAINER" });	

  resultPromise.then(adobeViewer => {
    adobeViewer.getAPIs().then(apis => {
      apis.getPDFMetadata()
      .then(result => {
        totalPages = result.numPages;
        console.log('totalPages', totalPages);
        listenForReads();
      })
      .catch(error => console.log(error));
    });
  });
	
}

function listenForReads() {
	
  const eventOptions = {
    listenOn: [ AdobeDC.View.Enum.PDFAnalyticsEvents.PAGE_VIEW ],
    enablePDFAnalytics: true
  }

  adobeDCView.registerCallback(
    AdobeDC.View.Enum.CallbackType.EVENT_LISTENER,
    function(event) {
      /*
       console.log("Type " + event.type);
       console.log("Data " + JSON.stringify(event.data));
      */
      let page = event.data.pageNumber;
      pagesRead.add(page);
      console.log(`view page ${page}`);
      if(pagesRead.size === totalPages && !shownAlert) {
        alert('You read it all!');
        shownAlert = true;
      }
    }, eventOptions
  );

}

Cómo aprender más

Espero que esta introducción a la API Embed haya sido útil. Aquí hay algunos recursos para ayudarlo a profundizar en esto:

  • Comience examinando los documentos, ya que hace un gran trabajo al repasar todos los detalles.
  • Tenemos una demostración en vivo que le permite ver todo en acción e incluso generará código para usted.
  • Si tiene preguntas o necesita ayuda, tenemos un foro para preguntas y puede usar el adobe-embed-api en StackOverflow también.
  • Si necesita trabajar con archivos PDF a nivel de servidor, tenemos la API de herramientas de PDF de Adobe, así como una herramienta de generación de documentos de Adobe muy interesante que le puede gustar. Estos no son gratuitos como la API de inserción de PDF, pero puede probarlos durante seis meses y probarlos registrándose.

Por último, estamos absolutamente abiertos a recibir comentarios sobre esto. Si tiene sugerencias, ideas, preguntas o cualquier otra cosa, ¡no dude en comunicarse!

(Visited 9 times, 1 visits today)