Pdf.js: Corrupción o "negrita" aleatoria / aparente

Creado en 31 mar. 2016  ·  46Comentarios  ·  Fuente: mozilla/pdf.js

Enlace al archivo PDF:
default.pdf

Configuración:

  • Navegador web y su versión: Versión 49.0.2623.87 (64 bits) [el problema no es específico del navegador]
  • Sistema operativo y su versión: Linux Ubuntu 15.10 [no específico del sistema operativo]
  • Versión de PDF.js: [todos / 1.3.91]
  • Es una extensión: pdf.js incrustado en la aplicación

Pasos para reproducir el problema:

  1. Abrir repetidamente el visor
  2. A veces la visualización es correcta, a veces hay "negrita" aleatoria
  3. La frecuencia parece ser aleatoria
  4. Esto es CAUSADO por establecer "PDFJS.disableWorker = true;" (eliminar este problema soluciona)
  5. No puedo "no" inhabilitar al trabajador debido a la descarga masiva que esto causa en _todas_ vistas
  6. El contenido se carga desde una cadena en memoria
  7. He verificado que el contenido de la cadena es consistente entre las vistas Ok y corruptas
  8. En documentos de varias páginas, avanzar una página y luego retroceder siempre soluciona el problema

¿Cuál es el comportamiento esperado? (agregar captura de pantalla)
ok

¿Qué salió mal? (agregar captura de pantalla)
corrupt

1-other 4-chrome-specific

Todos 46 comentarios

No puedo "no" deshabilitar al trabajador debido a la descarga masiva que esto causa en cada vista

¿Podrías explicar esta parte?

Si está intentando utilizar getDocument varias veces, utilice una única instancia de PDFWorker. Es difícil saber qué está causando la corrupción de las fuentes, pero tener un enlace al ejemplo de trabajo podría arrojar algo de luz. ¿Puede crear / publicar un ejemplo que cause el problema?

Ok, no puedo publicar un enlace fácilmente. Si corro con los trabajadores habilitados, funciona al 100%. Si configuro el indicador de desactivación, verá el problema que se muestra arriba, al azar, tal vez 1 instancia de 4.

Me estaba dirigiendo a la respuesta de "solo habilite a los trabajadores" al detallar "por qué" estoy deshabilitando al trabajador, que es que estoy mostrando muchos PDF pequeños con bastante rapidez y agregando una descarga de 1.2Mb para pdf_worker.js para cada pantalla no es práctica. He estado mirando el código del trabajador web para ver si hay una opción para que los trabajadores almacenen en caché el script .js al que se les llama, pero no pude encontrar nada.

Mi suposición inicial (basada en el efecto) es que hay algo en algún lugar con un alcance global que se borra correctamente si el script se carga para cada instancia, que causa un problema si el trabajador con script se reutiliza repetidamente. Sin embargo (!) Dado que el problema puede ocurrir en la PRIMERA pantalla de pdf, estoy un poco perdido para saber qué mirar.

Me estaba dirigiendo a la respuesta de "solo habilite a los trabajadores" al detallar "por qué" estoy deshabilitando al trabajador, que es que estoy mostrando muchos PDF pequeños con bastante rapidez y agregando una descarga de 1.2Mb para pdf_worker.js para cada pantalla no es práctica.

@oddjobz Todavía no entiendo la preocupación. Con el trabajador discapacitado, usted _todavía_ descargando pdf.worker.js pero está sucediendo en el hilo principal. La configuración adecuada en el servidor web permite el almacenamiento en caché del archivo javascript estático y evita la descarga de 1.2Mb para cada solicitud sin esfuerzo adicional. PDFWorker ayudará con el almacenamiento en caché de instancias del trabajador web en una sola página (por ejemplo, cuando se realizan varios getDocuments).

No estoy seguro de si este problema está completo sin el código para su solución, de forma predeterminada, PDF.js almacena en caché el código del trabajador web cuando se usa en un servidor web estándar con un navegador estándar (en las configuraciones predeterminadas).

Bueno, no sé cuál es la diferencia entre el código que estoy usando y el código que tienes, pero hay una diferencia en alguna parte. En primer lugar, con el trabajador deshabilitado, el pdf_worker.js se carga una vez en el primer golpe "solo". Con los trabajadores habilitados, carga el código en cada documento nuevo y nada de lo que hago parece tener ningún efecto en el almacenamiento en caché. (es decir, no está almacenado en caché) Sospecho que debido a que los desarrolladores de Chrome tenían problemas con los trabajadores web y el código almacenado en caché, lo han desactivado. Por lo que puedo ver, todos mis encabezados son como deberían ser para el almacenamiento en caché, pero el almacenamiento en caché no está sucediendo. (mientras que otras cosas están en caché)

Tengo tres bits relevantes;
a. Bloque de código principal con una etiqueta de script
segundo. Onload que establece las variables globales
C. Una clase independiente que muestra un PDF en un DIV

bloque de código principal;

<script type="text/javascript" src="js/compatibility.js"></script>
<script type="text/javascript" src="js/pdf.js"></script>

código de carga;

    PDFJS.disableWorker = true;
    PDFJS.verbosity = PDFJS.VERBOSITY_LEVELS.debug;
    PDFJS.workerSrc = "/js/pdf.worker.js";

definición de clase;

JS.require('JS.Class',function(Class) {

    CLASS.PDFViewer = new Class({

        locked  : false,
        page        : 0,
        pages   : 0,
        pdf     : null,
        doc_id  : null,

        initialize: function(prefix) {
            this.canvas   = prefix+'-canvas';           // Canvas element ID we'll be rendering to
            this.prefix   = prefix;
            this.id_page  = '#'+this.canvas+'-page';    // Ident of page number
            this.id_pages = '#'+this.canvas+'-pages';   // Ident of page count
            this.setfocus(null);                        // Element to focus after render
        },
        reset:      function() { this.now_showing = null; console.log("PDF Reset")},
        set:        function(doc_id) { this.doc_id = doc_id; console.log("Docid:",doc_id) },
        load:       function() { this.fetch(this.doc_id); },
        set_doc:    function() {},
        setfocus: function(field_id) { this.focuson = field_id; },

        decode: function(base64) {
            var raw = atob(base64);
            var uint8Array = new Uint8Array(raw.length);
            for (var i = 0; i < raw.length; i++) {
                uint8Array[i] = raw.charCodeAt(i);
                }
          return uint8Array;
        },

        full_screen: function() {
            if( $('#'+this.prefix+'-hide-me').is(':visible') ) {
                $('#'+this.prefix+'-hide-me').hide();
                $('#'+this.prefix+'-full-screen').removeClass("col-sm-7");
                $('#'+this.prefix+'-full-screen').addClass("col-sm-12");
            } else {
                $('#'+this.prefix+'-hide-me').show();
                $('#'+this.prefix+'-full-screen').removeClass("col-sm-12");
                $('#'+this.prefix+'-full-screen').addClass("col-sm-7");
            }
            this.turn_page();
        },
        focus: function() {
            if(this.focuson) {
                console.log("SetFocus>>",this.focuson);
                setTimeout("$('"+this.focuson+"').focus()",100);
                this.focuson = null;
            }
        },
        display: function(pdf) {
            this.pdf = pdf;
            $(this.id_pages).text(this.pdf.numPages);
            this.pages = this.pdf.numPages;
            this.page = 1;
            this.turn_page();
        },
        fetch: function(rid) {
            if(this.locked) return false;
            var self = this;
            var src = '/images/default.pdf';
            function success(data) {
                if(!LIB.check_error(data)) return false;
                if(data.pdf) src = self.decode(data.pdf);
                self.locked = true;
                PDFJS.getDocument(src).then(function(pdf){ self.display(pdf); });
                return true;
            }
            ionman.call('nac.rpc.pdf_spec',{'rid': rid},success)
            return true;
        },
        turn_page: function() {
        var self = this;
            self.pdf.getPage(self.page).then(function(page) {
                var canvas = document.getElementById(self.canvas);
        var ctx = canvas.getContext('2d');
        var unscaledViewport = page.getViewport(1.0);
                canvas.width = $('#'+self.canvas).width();
                var scale = canvas.width / unscaledViewport.width;
                var viewport = page.getViewport(scale);
                canvas.height = viewport.height;
            var renderContext = { canvasContext: ctx, viewport: viewport };
        page.render(renderContext).promise.then(function(){
                setTimeout(function(){
                    self.locked = false;
                        self.focus();
                    },250);
                });
                $(self.id_page).text(self.page);
            });
        },
        next: function() {
            if( this.page == this.pages) return;
            this.page += 1;
            this.turn_page();
        },
        prev: function() {
            if( this.page == 1) return;
            this.page -= 1;
            this.turn_page();
        }
    });

Así que hago;

var viewer = CLASS.PDFViewer('pdf');
viewer.fetch();

Y obtengo el documento predeterminado es un DIV con ID "pdf-canvas".

Intentemos esto:

  1. Abra http://mozilla.github.io/pdf.js/web/viewer.html en Chrome
  2. Abra devtools en la página de red y muestre la consola dividida (presione 'esc' en esta pestaña)
  3. Asegúrese de que no esté atrapado en una excepción (deshabilite el salto de excepción y actualice de lo contrario)
  4. Asegúrese de que "Desactivar caché" esté desactivado (desmarque y actualice de lo contrario)
  5. En la consola, ejecute PDFJS.getDocument('http://mozilla.github.io/pdf.js/web/compressed.tracemonkey-pldi-09.pdf')
  6. Observe que el segundo "pdf.worker.js" tiene el estado "200 OK (desde caché)"

screen shot 2016-03-31 at 10 51 26 am

Los fragmentos de código no son útiles. Implemente un pequeño ejemplo en algún lugar (por ejemplo, en las páginas de github)

Sí, lo veo ... parece ser una versión más reciente de PDF.js de la que estoy usando ... suponiendo que la diferencia no sea el problema, compararé los encabezados que Varnish está publicando con mi servidor web para ver si Puedo detectar por qué no se almacena en caché.

Más bien sospecho que debido a que los desarrolladores de Chrome tenían problemas con los trabajadores web y el código en caché, lo han desactivado.

No veo una conexión entre esto y la opción disableWorker. Se solicita pdf.worker.js independientemente de que sea verdadero o falso. Por tanto, el problema debe ser irrelevante para el almacenamiento en caché.

Por simplicidad, supongo que está relacionado con cómo funciona la mensajería en modo disableWorker (que no está realmente probado y creado solo para admitir navegadores heredados y facilitar la depuración). Ayudará a reducir el problema para tener un caso de prueba mínimo donde el problema es visible (preferiblemente accesible en línea).

Ok, esto es interesante ... prueba contra localhost: 8443 en un certificado ficticio (donde el nombre de host! = Localhost), no almacena en caché. Cuando pruebo contra el servidor en vivo, el puerto 443 con un certificado comercial válido, hace caché (!) ... no estoy muy seguro de qué hacer con eso ... haré más pruebas cuando tenga un poco de tiempo, pero para ahora habilitaré a los trabajadores web y veré qué sucede. (pero creo que todavía hay un problema en alguna parte ...)

No estoy del todo seguro de creerme ... así que agregué algunas capturas de pantalla ...

live

dev

Deshabilitar la caché definitivamente no está marcada ...
(la configuración del servidor web es idéntica)

¿Hay algo más que hacer aquí? Por lo que tengo entendido, esto no parece un error en PDF.js, sino más bien en la implementación personalizada.

Sería bueno tener un caso de prueba en el que podamos reproducir esta falla (¿intermitente?).

Es un error, produciré una demostración en línea, pero llevará algo de codificación y un poco de tiempo ...

Hola, tengo el mismo problema.

No escrito nada personalizado aquí, acabo de descargar el repositorio de Github
screencapture 7

@ subhadip-codeclouds No creo que tengas el mismo problema. Abra una edición separada y proporcione los detalles solicitados.

@ subhadip-codeclouds ¿Dónde puedo encontrar este pdf? Tengo un problema similar y me gustaría usarlo como caso de prueba.

Creo que tengo el mismo problema de renderizado de fuentes en Ubuntu con Chrome (no he probado otras plataformas). Estoy usando el archivo pdf.js más reciente del maestro y, a veces, un PDF se verá como el PDF de @oddjobz y, a veces, se verá como el PDF de @ subhadip-codeclouds. Esto parece suceder al azar en archivos PDF aleatorios.

Realmente no sé qué está mal o cómo reproducirlo de manera confiable. Sin embargo, este es el escenario. Estoy usando React para crear un sitio web dinámico de una sola página. Los usuarios a menudo hacen clic en una pestaña y eso creará un iframe y mostrará pdf.js dentro del iframe. Dada la forma en que React y mi sitio web funcionan, se crea y destruye un iframe una y otra vez. Puede llevar un tiempo, pero eventualmente siempre obtendré daños en el renderizado de fuentes. Y una vez que suceda para un PDF, comenzará a suceder con otros PDF al azar. Algunos siempre están bien y otros no.

¿Hay algo (por ejemplo, indicadores de depuración) que pueda activar o hacer para ayudar a averiguar qué está pasando? No veo ningún error ni advertencia en la consola.

Aquí hay un PDF que casi siempre termina con la corrupción de la fuente cuando se inicia.
https://datalanche-sec-public.s3.amazonaws.com/filings/0001047469-15-008315/a2226328zex-31_2.htm.pdf

Una cosa más. Si abro una nueva pestaña en Chrome con la misma URL, los archivos PDF se arreglan. Sin embargo, si permanezco en la misma pestaña, navego a un sitio web completamente diferente y luego navego a mi sitio web (sin usar el botón de retroceso), los PDF con fuentes corruptas todavía están corruptos. Casi parece que lo que está sucediendo está corrompiendo la memoria y / o el caché de la pestaña.

Posiblemente sea un problema de almacenamiento en caché en Chrome (consulte https://github.com/mozilla/pdf.js/issues/7751#issuecomment-256683285 para obtener más detalles).

¿Algún avance en esto? tener el mismo problema

Aunque todavía veo esto (inexplicablemente) en ocasiones, es muy raro y, de hecho, lo suficientemente raro, realmente dejé de preocuparme por eso. El problema que parecía tener era la superposición de operaciones. "Parece" posible operar en un documento pdf (página siguiente, por ejemplo) mientras otra operación aún está en progreso, y es esto lo que parece causar el problema. Mi solución fue envolver todas las operaciones en una clase, luego insertar un candado maestro en los puntos de entrada y salida para que ninguna operación relacionada con PDF pudiera entrar en conflicto - esto "parece" haber arreglado las cosas para mí. Supongo vagamente que los archivos PDF se ejecutan en un hilo o proceso de trabajo separado, de ahí la posibilidad de un conflicto. Fue hace un tiempo, pero de memoria creo que el tema del subproceso es una opción y descubrí la solución al deshabilitarlo, lo que tuvo un impacto negativo en el rendimiento, pero resolvió el problema.

Me pasa todo el tiempo, pero es tan aleatorio que no puedo crear un caso de prueba. Sin embargo, es muy posible que también se trate de daños en la memoria por subprocesos en mi caso, pero pensé que Javascript era de un solo subproceso.

Pensé que Javascript era de un solo hilo

Es. Creo que lo que @oddjobz significa (?) Que puede haber un error en Chrome cuando pinta en más de un lienzo HTML5 a la vez, el defecto tiene una alta probabilidad de ocurrir. Pero sin un caso de prueba reproducible, es difícil especular y crear un informe significativo para los errores de Chromium.

Creo que (desde la memoria) emplea la opción de usar una nueva función del navegador llamada "trabajadores web", que efectivamente te permite crear subprocesos javascript ... si desactivas esta función, intenta ver un PDF "grande", ver "por qué" esta función está en uso ... :)

emplea la opción de utilizar una nueva función de navegador llamada "trabajadores web" ...
si desactiva esta función, luego intenta ver un PDF "grande", verá "por qué" esta función está en uso

Tenga en cuenta que OP indica que desactive esta función, lo que significa que los Web Workers no se utilizan, lo que lleva la culpa al navegador y no tiene nada que ver con el "subproceso" de JavaScript.

Es un poco sutil, Javascript es de un solo subproceso, pero Chrome es de múltiples subprocesos y los trabajadores web le permiten ejecutar dos procesos de Chrome y facilita la comunicación entre ellos. Creo que solo el maestro tiene acceso al DOM, pero puede usar subprocesos para cosas intensivas en el procesador sin bloquear el subproceso de la interfaz de usuario. Se vuelve más divertido cuando descubres que puedes crear trabajadores web que no están adjuntos a un hilo o pestaña específico, por lo que sobreviven efectivamente a la recarga de una página (es decir, son persistentes). Veo muchos problemas derivados de esto ...

Claro, pero mi comentario es que sin subprocesos (es decir, implementando mi propio bloqueo de nivel de subprocesos), el 99% de este problema desaparece. (para mi).

@oddjobz , @rpedela intente deshabilitar la aceleración de hardware / gpu y vea si el problema

@yurydelendik , sí, eso fue obvio, una de las primeras cosas que probé. (ninguna diferencia)

@yurydelendik , mi aplicación ha estado

Javascript es de un solo subproceso, pero Chrome es de varios subprocesos, y los trabajadores web le permiten ejecutar dos procesos de Chrome y facilita la comunicación entre ellos. Creo que solo el maestro tiene acceso al DOM, pero puede usar subprocesos para cosas intensivas en el procesador sin bloquear el subproceso de la interfaz de usuario.

Esta declaración con el término "trabajador web" es confusa. ¿Puede proporcionar referencias para verificar las afirmaciones anteriores? Los Web Workers no tienen acceso al DOM por diseño, y PDF.js realiza la pintura en el hilo principal. ¿Te refieres al proceso de renderizado de Chrome? Aún así, la única forma de actualizar DOM es desde el hilo principal y no desde los trabajadores web.

El proceso comienza antes de que el anterior haya terminado, enhebrado o no, colocando un bloqueo manual para evitar que las operaciones se inicien antes de que el anterior haya terminado.

¿Qué quiere decir exactamente con "operaciones" en este contexto, es la vida útil de la llamada render() de la API?

@oddjobz Acabo de leer el hilo de nuevo y hay muchas declaraciones en conflicto en diferentes períodos de tiempo. Además, la sección de configuración también está en conflicto, por ejemplo, no puedo reproducir eso localmente en ningún navegador en Mac OSX. Todavía no estoy seguro de si puede reproducirlo con el visor estándar (no con el personalizado). Cerraré este error como no válido / incompleto para no confundir a otros participantes del hilo.

@oddjobz , @rpedela , @badams , @pholisma , @ subhadip-codeclouds ¿puede proporcionar un informe de error por separado con las configuraciones exactas en las que está experimentando el problema y los pasos exactos cuando se puede reproducir el problema (incluido el PDF)? si es una solución personalizada, proporcione un enlace público.

Ok, este es el código en cuestión, puede ver la solución en su lugar.

Específicamente para bloquear, tengo una rutina así;


this.locked = true;
PDFJS.getDocument(path+doc_id).then(function(pdf) {
    $('#pdf-canvas-pages').text(pdf.numPages);
    self.pages = pdf.numPages;
    self.page = 1;
    self.pdf = pdf;
    pdf.getPage(1).then(function(page) { self.turnpage(); });
})

turnpage: function() {
    var self = this;
    self.pdf.getPage(self.page).then(function(page) {
        var canvas = document.getElementById('pdf-canvas');
        var ctx = canvas.getContext('2d');
        var unscaledViewport = page.getViewport(1);
        canvas.width = $('#pdf-canvas').width();
        var scale = canvas.width / unscaledViewport.width;
        var viewport = page.getViewport(scale);
        canvas.height = viewport.height;
        var renderContext = { canvasContext: ctx, viewport: viewport };
        page.render(renderContext);
        $('#pdf-canvas-page').text(self.page);
        self.locked = false;
    });
},

Sí, es por eso que no insistí en ese punto en ese momento, parece haber una gran renuencia a aceptar incluso que hay un problema, y ​​mucho menos que debe solucionarse.

El problema con el fragmento anterior fue abordado por https://github.com/mozilla/pdf.js/pull/6571

Bueno, qué puedo decir, estaba usando la última versión a mediados de 2016 y todavía tenía el problema. Creo recordar que me dijeron en ese momento (repetidamente) que estaba arreglado. (y como muchos otros, pude ver que demostrablemente no lo era)

De todos modos, para cualquiera que esté viendo el mismo problema, intente colocar un candado como el anterior y vea si hace alguna diferencia ... son solo dos líneas ...

@yurydelendik Esto está sucediendo de manera bastante consistente para nuestros usuarios (principalmente con Windows 7), pero he podido reproducirlo en OSX con la última versión, pero no al 100% de manera consistente.

No estamos usando ningún código personalizado, simplemente hacemos lo siguiente

<iframe
    style="height: 650px; width: 600px"
    src="/path/to/pdfjs/web/viewer.html?file=/path/to/file.pdf"
/>

Parece depender de una serie de factores, como si hay algún otro texto en negrita en el documento y el nivel de zoom inicial (acercar y alejar a veces lo solucionará). También he notado que esto solo afecta a la vista previa, e imprimiendo, al descargar el pdf parece que se renderiza perfectamente (supongo que eso es porque pdf.js simplemente pasa el archivo proporcionado al usuario).

Hemos decidido dejar de usar esta solución y descargar el archivo directamente en la máquina de los usuarios, pero intentaré hacer algo de tiempo para crear un caso de prueba reproducible, aunque ayer pasé todo el día persiguiendo este error.

@badams , puedo confirmar que el zoom también fue una solución para mí, al igual que una página siguiente / anterior. También tenía la impresión de que la negrita hacía que el problema fuera más probable.

Sin embargo, intentaré hacer algo de tiempo para crear un caso de prueba reproducible

@badams gracias, cualquier cosa que tome todas las variaciones cuando los contribuyentes intentan reproducir el problema en sus computadoras funcionará, y los ejemplos completos publicados en línea funcionan mejor (puede publicar un ejemplo completo en la rama gh-pages de un repositorio de github).

Hola chicos,

No entendí bien toda esta historia.
¿Existe ya una solución? ¿O algún tipo de implementación que debería hacer?

Saludos,
Tarcisio Pereira

No entendí bien toda esta historia.

No creo que nadie lo haga.

Este hilo se cerró ya que no proporciona los pasos exactos para reproducir el problema (y debido a algunas recomendaciones engañosas en los comentarios). No esperamos que el problema sea reproducible al 100%, pero hacer que aparezca al menos una de cada 10 veces será genial.

Posibles elementos que pueden hacer que PDF.js funcione de esta manera o tenga un error en su código:

  • Un servidor o navegador HTTP no maneja correctamente las solicitudes de rango HTTP
  • Un navegador no maneja correctamente la carga de fuentes o el funcionamiento del lienzo
  • La solución personalizada entra en conflicto con las operaciones anteriores

FWIW He estado viendo esta corrupción en raras situaciones con nuestra implementación de pdf.js (v1.7.376). Nuestro manejo de solicitudes de rango parece correcto. Informaré si puedo encontrar pasos de reproducción confiables ...

Solo tuvimos este problema en Chrome, después de cambiar el zoom, desaparece. Así que configuramos showPreviousViewOnLoad en false y nunca volvimos a tener este problema.

@TZanke, ¿ podría aclarar por qué eliminar showPreviousViewOnLoad cambiaría el zoom? ¡Gracias!

@tonyjin pdf.js autozoom calcula un valor de zoom y lo guarda en el almacenamiento local. Después de volver a cargar la página, no se utiliza el zoom automático, sino que se utiliza el valor de zoom calculado anteriormente. Y parece que hay un problema al cargar este valor nuevamente.

Entonces, al deshabilitar showPreviousViewOnLoad la función de zoom automático se activa cada vez, amplía la página correctamente y no se producen problemas de renderizado.

@TZanke -

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

Temas relacionados

SehyunPark picture SehyunPark  ·  3Comentarios

aaronshaf picture aaronshaf  ·  3Comentarios

dmisdm picture dmisdm  ·  3Comentarios

sujit-baniya picture sujit-baniya  ·  3Comentarios

anggikolo11 picture anggikolo11  ·  3Comentarios