如何修复此错误在多个渲染()操作期间无法使用相同的画布

Posted

技术标签:

【中文标题】如何修复此错误在多个渲染()操作期间无法使用相同的画布【英文标题】:how to fix this Error Cannot use the same canvas during multiple render() operations 【发布时间】:2019-02-10 16:01:32 【问题描述】:

我在反应中使用画布,并使用画布将 pdf 渲染为图像。

现在,当我获得新数据时,即添加了另一个 pdf 文件,然后 再次必须为此使用画布。

我不确定如何修复此错误或如何移除画布,甚至在再次使用之前清除画布。

以下是相关代码:

 pdfLoop = (item,index) => 
        var that = this;
        PDFJS.getDocument(item).then(function getPdfHelloWorld(pdf) 
             //
             // Fetch the first page
             console.log('url is : ',item);
             pdf.getPage(1).then(function getPageHelloWorld(page) 
               var scale = 0.5;
               var viewport = page.getViewport(scale);


                   let cref = 'canvas'+index;
                   let imgref ='img'+index;
                   console.log('cref no : ',cref);
                   console.log('img no : ',imgref);

                   // Prepare canvas using PDF page dimensions
                   //
                   var canvas = that.canvasRefs[cref];
                   //let imagez = that.imageRefs[imgref];
                   var context = canvas.getContext('2d');
                   context.globalcompositeoperation = 'source-over';
                  // context.fillStyle = "#fff";
                  //draw on entire canvas
                  //context.fillRect( 0, 0, canvas.width, canvas.height );
                   canvas.height = viewport.height;
                   canvas.width = viewport.width;

                    //imagez.src = canvas.toDataURL("image/png");
                   //
                   // Render PDF page into canvas context
                   //
                   //page.render(canvasContext: context, viewport: viewport);
                   var task = page.render(canvasContext: context, viewport: viewport)
              task.promise.then(function()
                //console.log(canvas.toDataURL('image/png'));
                let imgItem = imgref:canvas.toDataURL('image/png'),page:index+1,rotate:0

                 let newState = that.state.imgsrc;
                 newState[index] = imgItem;
                 //let newState = that.state.imgsrc.concat(imgItem);
                that.setState(
                    imgsrc:newState
                );
                //imagez.src = canvas.toDataURL('image/png')
              );

             );
           );
       

【问题讨论】:

【参考方案1】:

如果有人偶然发现此问题,错误消息会显示以下Use different canvas or ensure previous operations were cancelled or completed.

在获取文档时,如果已经有文档,则必须将其销毁。即:

PDFJS.getDocument( url: pdf_url ).promise
    .then((pdf_doc) => 

        if (this.pdf_doc) 
            this.pdf_doc.destroy();
        
        this.pdf_doc = pdf_doc;
        this.total_pages = this.pdf_doc.numPages;
    )

我不知道这是否是一个好的解决方案,但至少它对我有用。

【讨论】:

【参考方案2】:

我在使用 PDF.js 时遇到了完全相同的问题,解决方案是, 渲染完成后,您必须清除 上下文

if (context) 
    context.clearRect(0, 0, canvas.width, canvas.height);
    context.beginPath();

这将确保上下文被清除并为下一次渲染做好准备,并且错误消失。

这对我有用。

【讨论】:

遗憾的是,这并没有为我解决。在我的情况下,它试图在第一次尚未完成渲染时再次加载另一个相同的 pdf。我想我需要等待第一个过程完成或取消它。你会怎么做这两件事? 晚会很晚。 PDFJS.getDocument() 返回的对象,具有promise 字段,也具有cancel 函数。调用它,它将取消当前渲染并拒绝promise 对象。然后,您可以再次安全地拨打PDFJS.getDocument()【参考方案3】:

为了避免这种情况,请将你的canvas对象放在一个div对象中,如下所示:

<div id="div_canvas">
    <canvas id="cnv"></canvas>
</div>

然后,在调用 pdf.js 函数之前,删除“div_canvas”内容并重新创建它:

$("#div_canvas").html("");
$("#div_canvas").html("<canvas id='cnv'></canvas>");

【讨论】:

【参考方案4】:

我和你有同样的问题,但我的解决方案与之前发布的答案有点不同。

对我而言,问题在于我在状态更改时不必要地重新渲染。检查您是否在未正确清除画布的情况下重新渲染组件,或者您是否甚至需要重新渲染(在我的情况下我没有)。

希望这能有所帮助

【讨论】:

【参考方案5】:

这很好用。我使用一个变量来存储实例并在加载其他文档之前将其销毁:

var PDFInstance: any = undefined
var currentSignature_axisX = 1
var currentSignature_axisY = 1

useEffect(() =>  if (pdfUrl != undefined) renderPDF() , [pdfUrl])
const renderPDF = async () => 

setLoadingPDF(true)
const urlSlice = pdfUrl.split('/')
const key = `$urlSlice[3]/$urlSlice[4]/$urlSlice[5]`

Storage.configure( customPrefix:  public: '' , )
const pdfS3URL = await Storage.get(key)

pdfjsLib.GlobalWorkerOptions.workerSrc = workerSrc
if (PDFInstance) PDFInstance.destroy()

PDFInstance = await pdfjsLib.getDocument(pdfS3URL).promise
const page = await PDFInstance.getPage(1)
const viewport = page.getViewport( scale: 1 )
const context = pdfCanvasRef.current?.getContext('2d');

setCanvasHeight(viewport.height)
setCanvasWidth(viewport.width)

const renderContext = 
  canvasContext: context,
  viewport: viewport,

await page.render(renderContext).promise
setLoadingPDF(false)

【讨论】:

【参考方案6】:

为了避免这种情况,请将您的画布对象放在一个 div 对象中,如下所示。 然后,在调用 pdf.js 函数之前,删除“div_canvas”内容并重新创建它:

"HTML"
<div id="div_canvas">
<canvas id="cnv"></canvas>
</div>
.....
"JS FILE"
$("#div_canvas").html("");
$("#div_canvas").html("<canvas id='cnv'></canvas>");

它对我来说很好,我希望它对某人有帮助!

【讨论】:

以上是关于如何修复此错误在多个渲染()操作期间无法使用相同的画布的主要内容,如果未能解决你的问题,请参考以下文章

如何使用 Remote-SSH 修复 VS Code 错误:“终端进程无法启动:启动期间发生本机异常(forkpty(3)失败。)。”?

如何修复使用 combine 解析 json 期间描述的错误?

如何在sails.js 中的SocketIO 握手期间修复“此套接字没有可用的有效会话”?

如何修复此错误 3734:无法在 MySQL WorkBench 上添加外键约束?

如何修复 Flutter 构建问题期间调用的 setState

如何在外部 COM 调用期间抑制“此操作无法完成”消息?