Pdf.js: 随机/明显的“螺栓连接” /损坏

创建于 2016-03-31  ·  46评论  ·  资料来源: mozilla/pdf.js

链接到PDF文件:
默认.pdf

组态:

  • Web浏览器及其版本:49.0.2623.87版(64位)[问题不是特定于浏览器的]
  • 操作系统及其版本:Linux Ubuntu 15.10 [非特定于操作系统]
  • PDF.js版本:[全部/ 1.3.91]
  • 是扩展:嵌入应用程序中的pdf.js

重现此问题的步骤:

  1. 反复打开查看器
  2. 有时显示还可以,有时会随机出现
  3. 频率似乎是随机的
  4. 这是通过设置“ PDFJS.disableWorker = true;”引起的。 (删除此修复程序问题)
  5. 由于无法在_every_视图上进行大量下载,因此我无法“禁用”该工作程序
  6. 内容是从内存中的字符串加载的
  7. 我已经验证了Ok和损坏的视图之间的字符串内容是一致的
  8. 在多页文档上,向前移动一页然后返回通常可以解决该问题

预期的行为是什么? (添加屏幕截图)
ok

什么地方出了错? (添加屏幕截图)
corrupt

1-other 4-chrome-specific

所有46条评论

我不能“不”禁用工作程序,因为这会在每个视图上导致大量下载

您能解释一下这部分吗?

如果您尝试多次使用getDocument,请使用单个PDFWorker实例。 很难说出是什么原因导致字体损坏,但是链接到工作示例可能会有所启发。 您可以创建/发布导致问题的示例吗?

好的,我无法轻松发布链接。 如果我在启用了工作程序的情况下运行,则它可以100%运行。 如果我设置了禁用标志,您会随机看到上面显示的问题,可能是4个实例中的1个。

我通过详细说明“为什么要禁用工作人员”来阻止“只是让工作人员受益”的响应,这是因为我正在相当快地显示许多小PDF,并为pdf_worker.js添加了1.2Mb的下载每个显示都不实际。 我一直在查看Web工作者代码,以查看是否有一个可供工作者缓存他们调用的.js脚本的选项,但是我没有找到任何东西。

我最初的猜测(基于效果)是,如果为每个实例加载了脚本,则某些区域的全局作用域将被正确清除,如果重复使用工作脚本,则会导致问题。 但是(!)鉴于问题可能出现在FIRST pdf显示屏上,所以我不知所措。

我通过详细说明“为什么要禁用工作人员”来阻止“只是让工作人员受益”的响应,这是因为我正在相当快地显示许多小PDF,并为pdf_worker.js添加了1.2Mb的下载每个显示都不实际。

@oddjobz我还是不明白这个问题。 在禁用了工作程序的情况下,您仍然_____下载pdf.worker.js,但它正在主线程中发生。 在网络服务器上正确设置可以缓存静态javascript文件,并避免为每个请求下载1.2Mb的内容,而无需付出额外的努力。 PDFWorker应帮助在单个页面上缓存Web Worker的实例(例如,执行多个getDocuments时)。

如果没有解决方案的代码,则不确定此问题是否完整,默认情况下,当在具有标准浏览器的标准Web服务器(默认配置)上使用PDF.js时,它会缓存Web工作者代码。

好吧,我不知道我正在使用的代码与您拥有的代码之间有什么区别,但是在某些地方存在差异。 首先,在禁用worker的情况下,第一次“仅”匹配时会一次加载pdf_worker.js。 启用worker后,它将在每个新文档上加载代码,而我所做的一切似乎对缓存没有任何影响。 (即,未缓存)我宁愿怀疑由于Chrome开发人员在Web工作者和缓存代码方面遇到问题,因此他们关闭了缓存。 据我所知,我的所有标头都与缓存相同,但是缓存没有发生。 (而其他内容已被缓存)

我有三个相关的方面;
一种。 带脚本标签的主代码块
b。 设置全局变量的Onload
C。 在DIV中显示PDF的独立类

主代码块;

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

加载代码;

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

类定义;

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

这样我

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

我得到的默认文档是ID为“ pdf-canvas”的DIV。

让我们尝试一下:

  1. 在Chrome中打开http://mozilla.github.io/pdf.js/web/viewer.html
  2. 在“网络”页面上打开devtools并显示拆分控制台(在此选项卡上单击“ esc”)
  3. 确保它没有陷入异常(禁用异常中断并以其他方式刷新)
  4. 确保“禁用缓存”已关闭(否则请取消选中并刷新)
  5. 在控制台中,执行PDFJS.getDocument('http://mozilla.github.io/pdf.js/web/compressed.tracemonkey-pldi-09.pdf')
  6. 注意第二个“ pdf.worker.js”的状态为“ 200 OK(来自缓存)”

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

代码段没有帮助。 请在某个地方部署小示例(例如,在github页面上)

是的,我看到了..这似乎是我正在使用的PDF.js的较新版本。.假设区别不是问题,我将比较Varnish放在我的Web服务器上的标头,看是否我可以发现为什么它不缓存。

我比较怀疑的是,由于Chrome开发人员在网络工作者和缓存代码方面遇到了问题,因此他们关闭了缓存。

我看不到此选项与disableWorker选项之间的连接。 无论是true还是false,都将请求pdf.worker.js。 因此,该问题必须与缓存无关。

为简单起见,我假定它与消息传递在disableWorker模式下的工作方式有关(该模型未经实际测试,并且仅用于支持旧版浏览器并易于调试)。 这将有助于缩小问题的范围,以使问题可见的最小测试案例(最好是可在线访问)。

好的,所以这很有趣..在虚拟证书(主机名!= localhost)上针对localhost:8443进行测试,它不会缓存。 当我使用有效的商业证书针对实时服务器(端口443)进行测试时,它确实会缓存(!)。现在,我将启用网络工作者,看看会发生什么。 (但我认为那里仍然存在问题……)

我不太确定我是否相信我..所以我添加了一些屏幕截图...

live

dev

禁用缓存肯定被_not_打勾...
(Web服务器配置相同)

还有什么要做的吗? 据我了解,这听起来不像是PDF.js中的错误,而是自定义实现中的错误。

有一个测试用例,我们可以重现这种(间歇性的)故障是很好的。

这是一个错误,我将进行在线演示,但这需要一些编码和一些时间...

嗨,我遇到了同样的问题。

这里没有编写任何自定义内容,只是从Github下载了回购协议
screencapture 7

@ subhadip-codeclouds我认为您没有相同的问题。 请另开一期并提供要求的详细信息。

@ subhadip-codeclouds在哪里可以找到此pdf文件? 我遇到类似的问题,想将其用作测试用例。

我相信我在使用Chrome的Ubuntu上遇到相同的字体渲染问题(尚未测试其他平台)。 我正在使用master的最新pdf.js,有时PDF看起来像@oddjobz的PDF,有时看起来像@ subhadip-codeclouds的PDF。 这似乎在随机PDF上随机发生。

我真的不知道哪里出了问题或如何可靠地复制它。 但是,这是方案。 我正在使用React构建一个动态的单页面网站。 用户通常会点击一个标签,该标签会创建一个iframe,并在iframe中显示pdf.js。 考虑到React和我的网站的工作方式,iframe会被创建并一遍遍销毁。 可能要花一些时间,但最终我总是会出现字体渲染损坏的情况。 一旦一个PDF发生,它将随机开始出现在其他PDF中。 有些总是很好,有些却不是。

有什么可以打开或执行的操作(例如调试标志),以帮助弄清楚发生了什么事情? 我在控制台中看不到任何错误或警告。

这是一个PDF,在启动时几乎总是以字体渲染损坏而告终。
https://datalanche-sec-public.s3.amazonaws.com/filings/0001047469-15-008315/a2226328zex-31_2.htm.pdf

还有一件事。 如果我在Chrome中使用相同的网址打开一个新标签,则这些PDF已修复。 但是,如果我停留在同一选项卡中,请导航到一个完全不同的网站,然后导航到我的网站(不使用“后退”按钮)带有损坏字体的PDF仍然会损坏。 似乎所有发生的事情都在破坏选项卡的内存和/或缓存。

这可能是Chrome中的缓存问题(有关更多详细信息,请参见https://github.com/mozilla/pdf.js/issues/7751#issuecomment-256683285)。

这事有进一步更新吗? 有同样的问题

尽管我偶尔还是会(莫名其妙地)看到它,但它非常罕见,而且实际上已经足够少了,我真的不再担心它了。 我似乎遇到的问题是操作重叠。 “似乎”有可能在进行另一种操作的同时对pdf文档进行操作(例如,下一页),这似乎是导致问题的原因。 我的解决方案是将所有操作包装在一个类中,然后在入口点和出口点上插入一个主锁,这样pdf相关操作就不会发生冲突-这种“似乎”对我来说是固定的。 我模糊地假设pdf内容在单独的线程或工作进程中运行,因此有发生冲突的可能性。 那是前一阵子,但是从内存中我认为线程是一种选择,我通过禁用它来发现解决方案,这对性能产生了负面影响,但确实解决了问题。

它总是发生在我身上,但是它足够随机,以至于我无法创建一个测试用例。 但是很可能我的情况也是线程破坏内存,但是我认为Javascript是单线程的吗?

我以为Javascript是单线程的

它是。 我认为@oddjobz的意思是(?),当您一次在多个HTML5画布上进行绘制时,Chrome中可能会出现错误,而缺陷发生的可能性很高。 但是,如果没有可重现的测试用例,就很难进行推测,并且无法为Chromium错误创建有意义的报告。

我认为(从内存中)它采用了使用名为“ Web Workers”的新浏览器功能的选项,该功能有效地允许您创建javascript线程..如果关闭此功能,然后尝试查看“大” PDF,看到“为什么”此功能正在使用中... :)

它采用了使用名为“网络工作者”的新浏览器功能的选项。
如果关闭此功能,然后尝试查看“大” PDF,则会看到“为什么”使用此功能

请注意,OP指示关闭此功能,这意味着未使用Web Worker,这归咎于浏览器,并且与JavaScript“线程”无关。

这有点微妙,Javascript是单线程的,但是Chrome是多线程的,并且Web worker允许您运行两个Chrome进程并促进它们之间的通信。 我认为只有主服务器才能获得DOM访问权限,但是您可以将子线程用于处理器密集型产品,而不会阻塞UI线程。 当您发现可以创建未附加到特定线程或选项卡的Web Worker时,它会变得更加有趣,因此它们可以有效地承受页面重新加载(即它们是持久的)。 我看到很多问题源于此...

当然-但是我的评论是,没有线程(即通过实现我自己的线程级别锁定),这个问题的99%就消失了。 (为了我)。

@oddjobz@rpedela尝试禁用硬件/ gpu加速,看看问题是否仍然出现。

@yurydelendik ,是的,很明显,这是我尝试的第一件事。 (没有不同)

@yurydelendik ,我的应用程序已经运行了6个月以上,我很高兴所有剩余的问题都是“不同的”,并且很可能是用户错误或偶尔出现的怪异文档。 我遇到的问题(虽然不一致,但是100%可重现)已经消失了。 (IMHO)是由文档操作之间的重叠引起的,即文档操作在上一个文档完成之前开始的过程-是否进行线程化,放入手动锁以防止在上一个文档完成修复之前开始的操作。 易于复制的示例是快速向前浏览文档并在上一页完全完成渲染之前进行“下一个”处理。

Javascript是单线程的,但是Chrome是多线程的,并且Web worker允许您运行两个Chrome进程并促进它们之间的通信。 我认为只有主服务器才能获得DOM访问权限,但是您可以将子线程用于处理器密集型产品,而不会阻塞UI线程。

这种带有“网络工作者”一词的陈述令人困惑。 您可以提供参考以验证上述陈述吗? Web Workers不能通过设计访问DOM,而PDF.js则在主线程上进行绘画。 您是说Chrome的渲染过程吗? 仍然更新DOM的唯一方法是从主线程而不是从Web Worker。

进程在前一个进程完成之前开始-是否线程化,插入手动锁以防止在前一个进程完成修复之前启动操作。

在这种情况下,“操作”到底是什么意思,是API的render()调用的生命周期吗?

@oddjobz我只是再次阅读该线程,并且在不同的时间段有很多冲突的语句。 另外,配置部分也有冲突,例如,我无法在Mac OSX上的任何浏览器上本地复制该部分。 我仍然不确定是否可以使用标准查看器(而不是自定义的查看器)重现它。 我将关闭此错误为无效/不完整错误,以免混淆其他线程参与者。

@oddjobz,@rpedela,@badams,@pholisma,@ subhadip-codeclouds可以为您提供详细的配置()你所遇到的问题和详细的步骤时,可以重现该问题(包括PDF)的单独的错误报告? 如果是自定义解决方案,请提供指向它的公共链接。

好的,这是有问题的代码-您可以看到相应的修复程序。

专门用于锁定,我有一个像这样的例程;


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

是的,这就是为什么我当时没有提出要点,为什么似乎非常不愿意接受问题,更不用说需要解决了。

上面的代码段问题已通过https://github.com/mozilla/pdf.js/pull/6571解决

好吧,我能说什么,我使用的是2016年中期的最新版本,但仍然有问题。 我确实记得当时(反复)被告知它已修复。 (和其他许多人一样,我可以证明事实并非如此)

无论如何,对于那里遇到相同问题的任何人,请尝试按上述方法插入锁,看看是否有任何区别..只有两行...

@yurydelendik这对于我们的用户(主要是使用Windows 7)来说一直在发生,但是我已经能够在OSX上以最新版本重现它,但并非100%一致。

我们没有使用任何自定义代码,只需执行以下操作

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

这似乎取决于许多因素,例如文档中是否还有其他粗体文本,以及初始缩放级别(放大和缩小有时会解决该问题),我还注意到这只会影响预览,并进行打印,下载pdf时似乎呈现完美(我想这是因为pdf.js只是将提供的文件传递给用户)。

我们已经决定不再使用此解决方案,而是直接将文件下载到用户计算机上,但是我将花一些时间来提出一个可重现的测试用例,尽管我昨天已经花了整整一天时间来解决这个错误。

@badams ,我可以确定缩放对我来说也是一个解决方法,就像下一页/上一页一样。 我还给人一种印象,即黑体使问题更可能发生。

我会花一些时间来提出一个可重现的测试用例

@badams谢谢,当贡献者试图在他们的计算机上重现该问题时,所有采取各种措施的方法都将起作用,并且完整的示例在线发布效果最佳(您可以在github repo的gh-pages分支上发布完整的示例)。

嗨,大家好,

我不理解整个故事。
已经有修复程序了吗? 还是我应该做的某种实现?

问候,
塔西西奥·佩雷拉(Tarcisio Pereira)

我不理解整个故事。

我认为没有人这样做。

由于未提供重现此问题的确切步骤(并且由于注释中的某些误导性建议),因此已关闭该线程。 我们认为问题不会100%重现,但至少每10次出现一次将是很好的。

可能导致PDF.js以这种方式执行或代码中存在错误的项目:

  • HTTP服务器或浏览器无法正确处理HTTP范围请求
  • 浏览器无法正确处理字体加载或画布操作
  • 自定义解决方案与上述操作冲突

FWIW在部署pdf.js(v1.7.376)的情况下,我很少看到这种损坏。 我们的范围请求处理似乎正确。 如果我能找到可靠的复制步骤,则会报告。

我们仅在Chrome上遇到过此问题,更改缩放后它会消失。 因此,我们将showPreviousViewOnLoadfalse ,再也不会遇到此问题。

@TZanke您能否阐明为什么删除showPreviousViewOnLoad会改变缩放比例? 谢谢!

@tonyjin pdf.js autozoom计算缩放值并将其保存到本地存储中。 重新加载页面后,不使用自动缩放,而是使用先前计算的缩放值。 而且看起来再次加载此值时出现问题。

因此,禁用showPreviousViewOnLoad时,自动缩放功能会启动,正确缩放页面,并且不会出现渲染问题。

@TZanke-我尝试了您的方法,但不幸的是,有时仍然会出现此问题。

此页面是否有帮助?
0 / 5 - 0 等级

相关问题

xingxiaoyiyio picture xingxiaoyiyio  ·  3评论

azetutu picture azetutu  ·  4评论

jigskpatel picture jigskpatel  ·  3评论

AlexP3 picture AlexP3  ·  3评论

PeterNerlich picture PeterNerlich  ·  3评论