Pdf.js: Aleatório / aparente "negrito" / corrupção

Criado em 31 mar. 2016  ·  46Comentários  ·  Fonte: mozilla/pdf.js

Link para arquivo PDF:
default.pdf

Configuração:

  • Navegador da Web e sua versão: Versão 49.0.2623.87 (64 bits) [o problema não é específico do navegador]
  • Sistema operacional e sua versão: Linux Ubuntu 15.10 [não específico do sistema operacional]
  • Versão PDF.js: [all / 1.3.91]
  • É uma extensão: pdf.js embutido no aplicativo

Etapas para reproduzir o problema:

  1. Abra o visualizador repetidamente
  2. Às vezes, a exibição está OK, às vezes há "negrito" aleatório
  3. A frequência parece ser aleatória
  4. Isso é CAUSADO pela definição de "PDFJS.disableWorker = true;" (remover este problema corrige)
  5. Não posso "não" desabilitar o trabalhador por causa do download massivo que isso causa em _cada_ visualização
  6. O conteúdo é carregado de uma string na memória
  7. Eu verifiquei que o conteúdo da string é consistente entre as visualizações OK e corrompidas
  8. Em documentos de várias páginas, avançar uma página e voltar sempre corrige o problema

Qual é o comportamento esperado? (adicionar captura de tela)
ok

O que deu errado? (adicionar captura de tela)
corrupt

1-other 4-chrome-specific

Todos 46 comentários

Não posso "não" desabilitar o trabalhador por causa do download massivo que isso causa em todas as visualizações

Você poderia explicar essa parte?

Se você estiver tentando usar getDocument várias vezes, use uma única instância de PDFWorker. É difícil dizer o que está causando a corrupção das fontes, mas ter um link para o exemplo de trabalho pode lançar alguma luz. Você pode criar / publicar um exemplo que causa o problema?

Ok, não consigo publicar um link com facilidade. Se eu executar com os workers habilitados, funciona 100%. Se eu definir o sinalizador de desativação, você verá o problema mostrado acima, aleatoriamente, talvez 1 instância de 4.

Eu estava evitando a resposta de "apenas habilite os trabalhadores" detalhando "por que" estou desabilitando o trabalhador, que é que estou exibindo muitos PDFs pequenos rapidamente e adicionando um download de 1,2 MB para pdf_worker.js para cada exibição não é prática. Estive examinando o código do web worker para ver se há uma opção para os workers armazenarem em cache o script .js em que foram chamados, mas não consegui encontrar nada.

Minha suposição inicial (com base no efeito) é que há algo em algum lugar com um escopo global que é limpo corretamente se o script for carregado para cada instância, que causa um problema se o script de trabalho for reutilizado repetidamente. No entanto (!) Como o problema pode ocorrer na exibição do FIRST pdf, estou um pouco sem saber o que olhar.

Eu estava evitando a resposta de "apenas habilite os trabalhadores" detalhando "por que" estou desabilitando o trabalhador, que é que estou exibindo muitos PDFs pequenos rapidamente e adicionando um download de 1,2 MB para pdf_worker.js para cada exibição não é prática.

@oddjobz Ainda não entendo a preocupação. Com o trabalhador deficiente, você _ainda_ baixa o pdf.worker.js, mas está acontecendo no tópico principal. A configuração adequada no servidor da web permite o armazenamento em cache do arquivo javascript estático e evita o download de 1,2 MB para cada solicitação sem esforço adicional. PDFWorker deve ajudar com o cache de instâncias do web worker em uma única página (por exemplo, quando múltiplos getDocuments são executados).

Não tenho certeza se esse problema está completo sem o código para sua solução, por padrão, o PDF.js armazena em cache o código do web worker quando usado no servidor da web padrão com navegador padrão (em configurações padrão).

Bem, não sei qual é a diferença entre o código que estou usando e o código que você tem, mas há um diferencial em algum lugar. Em primeiro lugar, com o trabalhador desabilitado, o pdf_worker.js é carregado uma vez no primeiro hit "apenas". Com os workers habilitados, ele carrega o código em cada novo documento e nada do que faço parece ter qualquer efeito no cache. (ou seja, não está em cache) Suspeito que, como os desenvolvedores do Chrome estavam tendo problemas com web workers e código em cache, eles o desativaram. Até onde posso ver, todos os meus cabeçalhos estão como deveriam estar para o cache, mas o cache não está acontecendo. (enquanto outras coisas _está_ em cache)

Eu tenho três bits relevantes;
uma. Bloco de código principal com uma tag de script
b. Onload que define as variáveis ​​globais
c. Uma classe autônoma que exibe um PDF em um DIV

bloco de código principal;

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

código onload;

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

definição de classe;

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();
        }
    });

Então eu faço;

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

E eu recebo o documento padrão é um DIV com ID "pdf-canvas".

Vamos tentar isso:

  1. Abra http://mozilla.github.io/pdf.js/web/viewer.html no Chrome
  2. Abra devtools na página Network e mostre o console dividido (pressione 'esc' nesta guia)
  3. Certifique-se de que não seja capturado em uma exceção (desative a quebra de exceção e atualize caso contrário)
  4. Certifique-se de que "Desativar Cache" esteja desativado (desmarque e atualize caso contrário)
  5. No console, execute PDFJS.getDocument('http://mozilla.github.io/pdf.js/web/compressed.tracemonkey-pldi-09.pdf')
  6. Observe que o segundo "pdf.worker.js" tem o status "200 OK (do cache)"

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

Trechos de código não são úteis. Implante um pequeno exemplo em algum lugar (por exemplo, nas páginas do github)

Sim, entendo ... parece ser uma versão mais recente do PDF.js do que estou usando ... presumindo que a diferença não é o problema, compararei os cabeçalhos que o Varnish está colocando no meu servidor da web para ver se Posso identificar por que não está em cache

Eu suspeito que, como os desenvolvedores do Chrome estavam tendo problemas com web workers e código em cache, eles desativaram o cache.

Não vejo uma conexão entre isso e a opção disableWorker. O pdf.worker.js é solicitado independentemente de ser verdadeiro ou falso. Portanto, o problema deve ser irrelevante para o cache.

Para simplificar, presumo que esteja relacionado ao modo como as mensagens funcionam no modo disableWorker (que não foi realmente testado e foi criado apenas para oferecer suporte a navegadores legados e facilidade de depuração). Isso ajudará a reduzir o problema ter um caso de teste mínimo onde o problema é visível (de preferência acessível online).

Ok, então isso é interessante .. testar contra localhost: 8443 em um certificado fictício (onde o nome do host! = Localhost), ele não armazena em cache. Quando eu testo no servidor ao vivo, porta 443 com um certificado comercial válido, ele armazena em cache (!) ... não tenho certeza do que fazer com isso .. farei mais alguns testes quando eu tiver um pouco de tempo, mas por agora vou habilitar os web workers e ver o que acontece. (mas acho que ainda há um problema em algum lugar ...)

Não tenho certeza se acredito em mim ... então adicionei algumas capturas de tela ...

live

dev

Desativar cache definitivamente _não_ está marcado ...
(a configuração do servidor web é idêntica)

Há mais alguma coisa a ser feita aqui? Pelo que entendi, isso não parece um bug no PDF.js, mas sim na implementação customizada.

Será bom ter um caso de teste em que possamos reproduzir essa falha (intermitente?).

É um bug, vou produzir uma demonstração online, mas vai demorar um pouco de codificação e um pouco de tempo ...

Olá, estou com o mesmo problema.

Não escrevi nada personalizado aqui, acabei de baixar o repositório do Github
screencapture 7

@ subhadip-codeclouds Acho que você não tem o mesmo problema. Abra a edição separada e forneça os detalhes solicitados.

@ subhadip-codeclouds Onde posso encontrar este pdf? Estou tendo um problema semelhante e gostaria de usá-lo como um caso de teste.

Eu acredito que estou tendo o mesmo problema de renderização de fonte no Ubuntu com Chrome (não testei outras plataformas). Estou usando o pdf.js mais recente do master e, às vezes, um PDF será semelhante ao PDF de

Eu realmente não sei o que está errado ou como reproduzi-lo de forma confiável. No entanto, este é o cenário. Estou usando o React para construir um site dinâmico de uma única página. Os usuários frequentemente clicarão em uma guia e isso criará um iframe e exibirá pdf.js dentro do iframe. Dada a maneira como o React e meu site funcionam, um iframe é criado e destruído continuamente. Pode demorar um pouco, mas eventualmente eu sempre terei corrupção de renderização de fonte. E quando isso acontecer com um PDF, começará a acontecer com outros PDFs aleatoriamente. Alguns estão sempre bem, outros não.

Existe alguma coisa (por exemplo, sinalizadores de depuração) que posso ativar ou fazer para ajudar a descobrir o que está acontecendo? Não vejo nenhum erro ou aviso no console.

Aqui está um PDF que quase sempre termina com corrupção de renderização de fonte quando é iniciado.
https://datalanche-sec-public.s3.amazonaws.com/filings/0001047469-15-008315/a2226328zex-31_2.htm.pdf

Mais uma coisa. Se eu abrir uma nova guia no Chrome com o mesmo URL, os PDFs serão corrigidos. No entanto, se eu permanecer na mesma guia, navegar para um site completamente diferente e, em seguida, navegar para o meu site (sem usar o botão Voltar), os PDFs com fontes corrompidas ainda estão corrompidos. Quase parece que o que está acontecendo está corrompendo a memória e / ou o cache da guia.

É possivelmente um problema de cache no Chrome (consulte https://github.com/mozilla/pdf.js/issues/7751#issuecomment-256683285 para obter mais detalhes).

alguma atualização disso? tendo o mesmo problema

Embora eu ainda veja isso (inexplicavelmente) de vez em quando, é muito raro e, na verdade, suficientemente raro que parei de me preocupar com isso. O problema que eu parecia ter era sobreposição de operações. "Parece" ser possível operar em um documento pdf (página seguinte, por exemplo) enquanto outra operação ainda está em andamento, e é isso que parece causar o problema. Minha solução foi agrupar todas as operações em uma classe e, em seguida, inserir um bloqueio mestre nos pontos de entrada e saída para que nenhuma operação relacionada ao pdf pudesse entrar em conflito - isso "parece" ter consertado as coisas para mim. Estou vagamente assumindo que as coisas do pdf são executadas em um thread ou processo de trabalho separado, daí a possibilidade de um conflito. Foi há pouco tempo, mas de memória acho que o threading é uma opção e descobri a solução desabilitando-o, o que teve um impacto negativo no desempenho, mas resolveu o problema.

Isso acontece comigo o tempo todo, mas é aleatório o suficiente para que eu não consiga criar um caso de teste. No entanto, é bem possível que seja corrupção de memória por threading no meu caso também, mas pensei que o Javascript fosse single threaded?

Achei que o Javascript fosse um único tópico

Isto é. Acho que @oddjobz significa (?) Que pode haver um bug no Chrome quando você pinta em mais de uma tela HTML5 ao mesmo tempo em que o defeito tem grande chance de ocorrer. Mas sem um caso de teste reproduzível é difícil especular e criar um relatório significativo para os bugs do Chromium.

Acho que (de memória) ele emprega a opção de usar um novo recurso do navegador chamado "web workers", que efetivamente permite que você crie threads de javascript .. se você desligar esse recurso, tente visualizar um PDF "grande", veja "por que" esse recurso está em uso ... :)

ele emprega a opção de usar um novo recurso do navegador chamado "web workers" ...
se você desativar esse recurso e tentar visualizar um PDF "grande", verá "por que" esse recurso está em uso

Observe que o OP instrui para desativar esse recurso, significa que Web Workers não são usados, o que passa a culpa para o navegador e não tem nada a ver com o "encadeamento" do JavaScript.

É um pouco sutil, Javascript é single threaded, mas o Chrome é multi-threaded, e os web workers permitem que você execute dois processos do Chrome e facilita a comunicação entre eles. Acho que apenas o mestre tem acesso ao DOM, mas você pode usar sub-threads para coisas intensivas do processador sem bloquear o thread da IU. Fica mais divertido quando você descobre que pode criar web workers que não estão vinculados a um tópico ou guia específico, para que sobrevivam efetivamente a uma recarga de página (ou seja, são persistentes). Vejo muitos problemas decorrentes disso ...

Claro - mas meu comentário é que sem threading (ou seja, implementando meu próprio bloqueio de nível de thread), 99% deste problema desaparece. (para mim).

@oddjobz , @rpedela tente desabilitar a aceleração de hardware / GPU e veja se o problema ainda ocorre.

@yurydelendik , sim, isso era óbvio, uma das primeiras coisas que tentei. (sem diferença)

@yurydelendik , meu aplicativo está no ar há mais de 6 meses, fico feliz que qualquer problema remanescente seja "diferente" e provavelmente seja um erro do usuário ou um documento estranho ocasional. O problema que eu estava tendo, que embora não fosse consistente, era 100% reproduzível, acabou. Foi (IMHO) causado pela sobreposição entre as operações do documento, ou seja, um processo iniciado antes do término do anterior - threading ou não, colocando um bloqueio manual para evitar que as operações iniciadas antes do término do anterior o consertassem. O exemplo facilmente reproduzido foi a digitalização rápida para a frente em um documento e tendo o "próximo" início de processamento antes que a página anterior tivesse terminado completamente a renderização.

Javascript é de thread único, mas o Chrome é multi-thread, e os web workers permitem que você execute dois processos do Chrome e facilita a comunicação entre eles. Acho que apenas o mestre tem acesso ao DOM, mas você pode usar sub-threads para coisas intensivas do processador sem bloquear o thread da IU.

Esta declaração com o termo "web worker" é confusa. Você pode fornecer referências para verificar as afirmações acima? Os Web Workers não têm acesso ao DOM por design, e o PDF.js executa a pintura no thread principal. Você quer dizer o processo de renderização do Chrome? Ainda assim, a única maneira de atualizar o DOM é a partir do thread principal e não dos web workers.

processos iniciados antes do término do anterior - rosqueamento ou não, colocando um bloqueio manual para evitar que as operações iniciem antes do término do anterior.

O que exatamente você quer dizer com "operações" neste contexto, é o tempo de vida da chamada render() da API?

@oddjobz Acabei de ler o tópico novamente e há muitas declarações conflitantes em diferentes períodos de tempo. Além disso, a seção de configuração é conflitante, por exemplo, não posso reproduzi-la localmente em nenhum navegador do Mac OSX. Ainda não tenho certeza se você pode reproduzi-lo com o visualizador padrão (não o seu personalizado). Fecharei este bug como inválido / incompleto para não confundir outros participantes do thread.

@oddjobz , @rpedela , @badams , @pholisma , @ subhadip-codeclouds você pode fornecer um relatório de bug separado com as configurações exatas de que você está tendo o problema e as etapas exatas para reproduzir o problema (incluindo o PDF)? se for uma solução personalizada, forneça um link público para ela.

Ok, este é o código em questão - você pode ver a correção no lugar.

Especificamente para travar, tenho uma rotina assim;


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;
    });
},

Sim, é por isso que não insisti no assunto na hora. Parece haver grande relutância em aceitar que há um problema - quanto mais que precisa ser corrigido.

O problema com o snippet acima foi resolvido por https://github.com/mozilla/pdf.js/pull/6571

Bem, o que posso dizer, estava usando a versão mais recente em meados de 2016 e ainda tinha o problema. Eu me lembro de ter ouvido na época (repetidamente) que estava consertado. (e como vários outros, pude ver que não era)

De qualquer forma, para quem está vendo o mesmo problema, tente colocar um cadeado como acima e veja se faz alguma diferença .. são apenas duas linhas ...

@yurydelendik Isso está acontecendo de forma bastante consistente para nossos usuários (principalmente no Windows 7), mas consegui reproduzi-lo no OSX com a versão mais recente, mas não 100% consistentemente.

Não estamos usando nenhum código personalizado, simplesmente fazendo o seguinte

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

Parece depender de uma série de fatores, como a existência de algum outro texto em negrito no documento e o nível de zoom inicial (aumentar e diminuir às vezes o corrige). Também percebi que isso afeta apenas a visualização, e imprimindo, ao baixar o pdf parece renderizar perfeitamente (acho que é porque pdf.js está apenas passando o arquivo fornecido para o usuário).

Decidimos deixar de usar esta solução e baixar o arquivo diretamente para a máquina do usuário, mas tentarei arranjar algum tempo para criar um caso de teste reproduzível, embora já tenha passado meu dia inteiro ontem perseguindo esse bug.

@badams , posso confirmar que o zoom também foi uma correção para mim, assim como a página seguinte / anterior. Também tive a impressão de que negrito tornava o problema mais provável.

Vou tentar arranjar algum tempo para encontrar um caso de teste reproduzível, embora

@badams obrigado, qualquer coisa que tenha todas as variações quando os colaboradores estão tentando reproduzir o problema em seus computadores funcionará, e exemplos completos publicados online funcionam melhor (você pode publicar o exemplo completo em um branch gh-pages do repositório do github).

Oi pessoal,

Eu não entendi direito toda essa história.
Já existe uma correção? Ou algum tipo de implementação que devo fazer?

Saudações,
Tarcisio Pereira

Eu não entendi direito toda essa história.

Acho que ninguém sabe.

Este tópico foi encerrado porque não fornece etapas exatas para reproduzir o problema (e devido a algumas recomendações enganosas nos comentários). Não esperamos que o problema seja reproduzível 100%, mas fazê-lo aparecer pelo menos uma vez em 10 vezes será ótimo.

Possíveis itens que podem fazer com que o PDF.js tenha este desempenho ou tenham um bug em seu código:

  • Um servidor ou navegador HTTP não lida adequadamente com solicitações de intervalo HTTP
  • Um navegador não está lidando corretamente com o carregamento de fontes ou operação de tela
  • A solução personalizada entra em conflito com as operações acima

FWIW Tenho visto essa corrupção em raras situações com nossa implantação de pdf.js (v1.7.376). Nosso tratamento de solicitação de intervalo parece correto. Apresentarei um relatório se encontrar etapas de reprodução confiáveis ​​...

Só tivemos esse problema no Chrome, depois de alterar o zoom ele desaparece. Portanto, definimos showPreviousViewOnLoad como false e nunca mais tivemos esse problema.

@TZanke você poderia esclarecer por que remover showPreviousViewOnLoad mudaria o zoom? Obrigado!

@tonyjin pdf.js autozoom calcula um valor de zoom e o salva no armazenamento local. Depois de recarregar a página, o zoom automático não é usado; em vez disso, o valor de zoom calculado anterior é usado. E parece que há um problema ao carregar esse valor novamente.

Portanto, ao desabilitar showPreviousViewOnLoad o recurso de zoom automático é ativado todas as vezes, aumenta o zoom da página corretamente e não ocorrem problemas de renderização.

@TZanke - Tentei sua abordagem, mas, infelizmente, o problema ainda surge às vezes .. :(

Esta página foi útil?
0 / 5 - 0 avaliações

Questões relacionadas

kleins05 picture kleins05  ·  3Comentários

timvandermeij picture timvandermeij  ·  4Comentários

anggikolo11 picture anggikolo11  ·  3Comentários

smit-modi picture smit-modi  ·  3Comentários

dmisdm picture dmisdm  ·  3Comentários