Pdf.js: No se puede imprimir PDF cuando se carga en iFrame

Creado en 11 oct. 2014  ·  21Comentarios  ·  Fuente: mozilla/pdf.js

Estoy intentando usar Javascript para enfocar e imprimir un archivo PDF que se carga dentro de un iframe que coloqué dinámicamente en el DOM. Este problema me está ocurriendo específicamente en Firefox.

Mi código se parece al siguiente:

<iframe name="printer_frame" id="printer_frame" src="http://domain.com/media/eparcel_label_1413020567.pdf"></iframe>
window.frames['printer_frame'].window.focus();
window.frames['printer_frame'].window.print();

Recibo el siguiente error:

Error: Permiso denegado para acceder a la propiedad 'imprimir'

Mi investigación me dice que esto debería funcionar, la lectura adicional me ha llevado a creer que esto puede ser un error. Cualquier ayuda sería apreciada.

Editar

Probé la funcionalidad reemplazando el archivo PDF con una captura de pantalla en formato PNG de la primera página y la función de impresión funcionó.

Editar

Pruebas adicionales. Agregué pdfjs a mi instalación de Chrome e intenté imprimir con el mismo código anterior. mismo error:

SecurityError: bloqueó un marco con origen " http://domain.com " para que no acceda a un marco de origen cruzado.

code: 18
message: "Blocked a frame with origin "http://domain.com" from accessing a cross-origin frame."
name: "SecurityError"
stack:
"Error: Blocked a frame with origin "http://domain.com" from accessing a cross-origin frame.
    at Error (native)
    at <anonymous>:2:34
    at Object.InjectedScript._evaluateOn (<anonymous>:730:39)
    at Object.InjectedScript._evaluateAndWrap (<anonymous>:669:52)
    at Object.InjectedScript.evaluate (<anonymous>:581:21)"

Debo aclarar que el archivo PDF se está cargando en el mismo dominio.

3-upstream 4-printing

Comentario más útil

Creo que sé la razón de esto, al menos en Firefox. En un ejemplo simple como el anterior, si usa Firefox DevTools para examinar document.domain tanto en la página principal como en el iframe, descubrí que document.domain es pdf.js para el renderizador PDF.js, por lo que las restricciones de origen cruzado del navegador se están activando.

Además, si construí PDF.js desde la fuente y configuré mi iframe en web/viewer.html?file= , luego llamé para decirle al iframe que imprimiera (como en el OP), funcionó bien.

¿Hay alguna forma de que PDF.js (al menos cuando se ejecuta en Firefox) acepte mensajes de otras ventanas, tal vez a través de algo como window.postMessage ? (Nunca lo he usado, así que no sé si es apropiado para este caso de uso o no).

Todos 21 comentarios

Posiblemente un duplicado del error 874200 .

Para cualquiera que se tope con este problema y desee una posible solución (considerando que este problema ha existido durante más de un año sin solución), terminé usando ImageMagick en PHP junto con GhostScript para generar imágenes del PDF en el servidor. , luego sirvió estas URL de imagen en una respuesta json, imprimiendo el resultado de eso fue trivial.

Conociéndome, sin embargo, probablemente haya una manera mejor y más fácil de hacerlo...

en about:config configuré pdfjs.disabled=true pero pdf comienza a descargar, supongo que si usa plugin.disable_full_page_plugin_for_types = application/pdf no puede descargar pdf y ver en el visor

Creo que sé la razón de esto, al menos en Firefox. En un ejemplo simple como el anterior, si usa Firefox DevTools para examinar document.domain tanto en la página principal como en el iframe, descubrí que document.domain es pdf.js para el renderizador PDF.js, por lo que las restricciones de origen cruzado del navegador se están activando.

Además, si construí PDF.js desde la fuente y configuré mi iframe en web/viewer.html?file= , luego llamé para decirle al iframe que imprimiera (como en el OP), funcionó bien.

¿Hay alguna forma de que PDF.js (al menos cuando se ejecuta en Firefox) acepte mensajes de otras ventanas, tal vez a través de algo como window.postMessage ? (Nunca lo he usado, así que no sé si es apropiado para este caso de uso o no).

Otra observación: esperaba activar la impresión a través del evento onload en el iframe , pero el PDF aún no se ha renderizado necesariamente. ¿No está seguro de si hay una manera confiable de verificar eso?

Vi # 5765, pero parece que solo se refiere a eventos a los que podría conectarse si estuviera ejecutando PDF.js directamente y no la versión integrada de Firefox.

Estoy desconcertado de que este sea un problema tan grande como para hacer algo tan simple como activar un archivo PDF para imprimir usando javascript. Este problema parece datar de dos o más años (posiblemente más) ahora.

¿Alguien ha encontrado una solución _del lado del cliente_? Vi la solución @Petce pero esa solución no funcionaría para mí.

No contenga la respiración @ Lynda333 , el soporte para este problema es notoriamente insensible. En mi opinión, su única opción real es encontrar un compromiso adecuado en la funcionalidad. Si nos cuenta más sobre su situación, yo y otros podríamos presentar una posible solución.

@Petce : no lo haré cuando vea hace cuánto tiempo comenzó este problema. Parece ridículo no incluir esta habilidad. Hablé con el cliente y voy a cambiar nuestro enfoque para este sitio. 1) Pueden descargar el PDF y 2) Estoy recreando parte del contenido del PDF en HTML y dejando que el usuario elija qué imprimir. Lleva más tiempo crearlo, pero funcionará.

¿Alguien puede imprimir iframe incrustado? acabo de instalar la última versión de la extensión y me deniegan el permiso de error, además, no puedo ver archivos pdf en el acceso normal a pdf.

Usando el código de estas confirmaciones (y el analizador de datos pdfjs en sí mismo), puede reescribir su pdf como un blob temporal y agregar una instrucción de impresión: https://github.com/mozilla/pdf.js/pull/6190/commits
Cree un iframe con el blob como fuente y comenzará a imprimirse (tenga en cuenta que, por ejemplo, no cargará blobs en iframes en absoluto, aparte de no seguir la instrucción de impresión).
De todos modos, esto es bastante complejo si aún no está ejecutando una versión personalizada del visor.
Alternativamente, puede agregar la instrucción de impresión en el servidor o en cualquier lugar donde pueda editar los datos del pdf.

La parte divertida es que solo Firefox lo necesita... Hace tres años que se informó este problema y Firefox es el único navegador que se queja de acceder a la ventana de contenido del iframe: parece que a nadie le importa imprimir hoy en día, lo que tal vez sea algo bueno.

Esto parece estar funcionando para mí

        setTimeout(function(){
            this.printIframeRef.contentWindow.document.getElementById('secondaryPrint').click()
        }.bind(this), 3000)

No pude encontrar ningún evento o forma de conectarme con el visor, pero si activa el clic incluso en sus botones de impresión (estoy usando la versión 1.4.20), parece que se imprime. El settimeout le da tiempo al espectador para cargar y tal

¿Puedes acceder a contentWindow en Firefox? ¿No tienes un problema de seguridad?

@paolocaminiti Estoy cargando todos los archivos del mismo dominio. Parece funcionar para mí. He usado IE 10 y 11, IE Edge, Chrome en Windows. Y FireFox 38 en Ubuntu 14.04.

    handlePrintClick() {
        blurComponentRef(this.printButtonRef)
        this.printIframeRef.contentWindow.document.getElementById('secondaryPrint').click()
    }

    handlePrintLoad() {
        this.printIframeRef.contentWindow.addEventListener("documentload", function(){
            this.setState({canPrint: true})
        }.bind(this));
    }

Veo que está cargando el pdf nuevamente desde el control remoto y resulta en el mismo dominio.
En Chrome/Opera/Safari estoy usando esto:

function directPrint () {
  PDFViewerApplication.pdfDocument.getData().then(function(res) {
    var b = URL.createObjectURL(new Blob([res], { type: 'application/pdf' }))
    var printFrame = document.getElementById('print-frame')
    if (!printFrame) {
      printFrame = document.createElement('iframe')
      printFrame.id = 'print-frame'
      printFrame.src = b
      document.body.appendChild(printFrame)
    }
    setTimeout(function () {
      printFrame.contentWindow.print()
      // ...dispose iframe and blob.
    }, 0)
  })
}

Simplemente usa los datos locales para crear un blob y luego llamar a imprimir, el setTimeout 0 permite adjuntar el iframe.

Desafortunadamente, Firefox no permite la ventana de contenido con el blob, pero un blob con una instrucción de impresión se imprimirá por sí solo.

Por ejemplo, no hay solución usando datos locales, pero tal vez tener un proxy en un servidor propio para enrutar los datos de pdf sería suficiente para permitir que todos sean del mismo dominio y aplicar su código.

Hola,

¿Qué significa "res"? ¿Y PDFViewerApplication proviene de PDF.js?

Gracias,

Sí, PDFViewerApplication es proporcionado por la compilación PDFViewer de pdfjs, la fuente está en el directorio /web, debe modificar allí y hacer una nueva compilación para que sea más fácil fusionar el repositorio maestro a medida que se actualiza...

res es solo el argumento devuelto por getData, debe ser la representación de bytes del archivo pdf, aquí se usa para crear una URL de blob local para cargar sin más solicitudes de red.

Si busca algo como el código anterior, es posible que desee limpiarlo un poco:

function directPrint () {
  var printFrame = document.getElementById('print-frame')
  if (printFrame) {
    printFrame.contentWindow.print()
  } else {
    PDFViewerApplication.pdfDocument.getData().then(function(res) {
      var src = URL.createObjectURL(new Blob([res], { type: 'application/pdf' }))
      printFrame = document.createElement('iframe')
      printFrame.id = 'print-frame'
      printFrame.style.display = 'none'
      printFrame.src = src
      document.body.appendChild(printFrame)
      setTimeout(function () {
        printFrame.contentWindow.print()
      }, 0)
    })
  }
}

Al final, opté por no desechar el iframe, ya que resultó complicado entender cuándo hacerlo, simplemente lo dejo allí y lo reutilizo cada vez que el usuario quiere imprimir, asumiendo que el pdf no puede cambiar en el medio.

Espero eso ayude.

@thenewguy Solo para aclarar este hilo para otros lectores, parece que estamos haciendo cosas bastante diferentes:
Estoy tratando de usar el visor de pdf del navegador nativo para imprimir en calidad total (no encontré ninguna forma de acceder a contentWindow tanto en ie como en edge, sin importar si se usa el mismo dominio).
Está cargando el visor de PDFjs en un iframe, posiblemente visible, y controlando su impresión desde la aplicación host.

Es divertido porque estaba tratando de lograr que @paolocaminiti insertara un script en mi iframe y lo llamara como una función, pero ahora obtengo "offsetParent no está configurado, no se puede desplazar" 😢. Usaré la impresión de quiosco de cromo y olvidé esto.

Hasta el momento no se ha propuesto ninguna solución

¿Todavía necesito tener una solución del lado del servidor o hay algún progreso en este tema? ¿Es posible usar el PDFPrintService de pdf-js? ¿Sería esta una solución funcional? En caso afirmativo, ¿cómo es posible usar este servicio sin tener que usar todo el visor de PDF?

¿Fue útil esta página
0 / 5 - 0 calificaciones