【问题标题】:How to add shapes to the canvas?如何在画布上添加形状?
【发布时间】:2019-05-25 21:34:27
【问题描述】:

我想要

  • 为保存当前页面 pdf 的每个画布添加矩形形状
  • 每个页面中的形状可以出现 n 次。

问题

  • 为什么我的形状也替换了 pdf?
  • 无法将矩形形状添加到保存当前页面 pdf 的每个画布

以下是我尝试过的。 https://jsfiddle.net/goteL3hn/

代码:

// Adding a rectangle
jQuery(function($) {

    $("#addRectangle").click(function() {
    fCanvas = new fabric.Canvas("the-canvas", {
        selection: false
    });
        fCanvas.add(new fabric.Rect({
            left: 100,
            top: 100,
            fill: 'red',
            width: 20,
            height: 20
        }));
    });
});

【问题讨论】:

    标签: javascript html5-canvas fabricjs pdfjs


    【解决方案1】:

    您在 canvas the-canvas 元素中渲染 PDF,但在添加 rect 对象时,您使用相同的元素创建了 fabricjs canvas the-canvas 元素,因此它清除了画布并仅绘制了 rect 对象。

    您需要在 fabricjs 画布顶部上下文中呈现 pdf 页面数据,并在加载图像后将其作为图像对象添加到下部画布元素中。

    演示

    // If absolute URL from the remote server is provided, configure the CORS
    // header on that server.
    var url = 'https://raw.githubusercontent.com/mozilla/pdf.js/ba2edeae/web/compressed.tracemonkey-pldi-09.pdf';
    
    // Loaded via <script> tag, create shortcut to access PDF.js exports.
    var pdfjsLib = window['pdfjs-dist/build/pdf'];
    
    // The workerSrc property shall be specified.
    pdfjsLib.GlobalWorkerOptions.workerSrc = '//mozilla.github.io/pdf.js/build/pdf.worker.js';
    
    var pdfDoc = null,
      pageNum = 1,
      prevPageNum = 1,
      pageRendering = false,
      pageNumPending = null,
      scale = 0.8,
      fCanvas = new fabric.Canvas("the-canvas", {
        selection: false
      });
    /**
     * Get page info from document, resize canvas accordingly, and render page.
     * @param num Page number.
     */
    var pageHistory = {};
    
    function renderPage(num) {
      pageHistory[prevPageNum] = fCanvas.toJSON();
      var jsonData = pageHistory[num];
      fCanvas.discardActiveObject(); //if you have any object selected, then it will deselect
      if (jsonData) {
        fCanvas.loadFromJSON(jsonData, function() {
          renderPdfData(num);
          fCanvas.renderAll.bind(fCanvas)
        });
      } else {
        pageHistory[num] = fCanvas.toJSON();
        fCanvas.clear();
        renderPdfData(num);
      }
    
    }
    
    function renderPdfData(num) {
      pageRendering = true;
      // Using promise to fetch the page
      pdfDoc.getPage(num).then(function(page) {
        var viewport = page.getViewport(scale);
        fCanvas.setDimensions({
          height: viewport.height,
          width: viewport.width
        })
    
        // Render PDF page into canvas context, use fabricjs top canvas element context
        var renderContext = {
          canvasContext: fCanvas.contextTop,
          viewport: viewport
        };
        var renderTask = page.render(renderContext);
    
        // Wait for rendering to finish
        renderTask.promise.then(function() {
          pageRendering = false;
          var imageData = fCanvas.upperCanvasEl.toDataURL(); //create an image from top context and put it in lower canvas element
          fabric.Image.fromURL(imageData, function(img) {
            img.set({
              left: 0,
              top: 0,
              evented: false,
              selectable: false,
              excludeFromExport:true
            });
            fCanvas.add(img).sendToBack(img);
            fCanvas.clearContext(fCanvas.contextTop);
            if (pageNumPending !== null) {
              // New page rendering is pending
              renderPage(pageNumPending);
              pageNumPending = null;
            }
          });
        });
      });
    
      // Update page counters
      document.getElementById('page_num').textContent = num;
    }
    /**
     * If another page rendering in progress, waits until the rendering is
     * finised. Otherwise, executes rendering immediately.
     */
    function queueRenderPage(num) {
      if (pageRendering) {
        pageNumPending = num;
      } else {
        renderPage(num);
      }
    }
    
    /**
     * Displays previous page.
     */
    function onPrevPage() {
      if (pageNum <= 1) {
        return;
      }
      prevPageNum = pageNum;
      pageNum--;
      queueRenderPage(pageNum);
    }
    document.getElementById('prev').addEventListener('click', onPrevPage);
    
    /**
     * Displays next page.
     */
    function onNextPage() {
      if (pageNum >= pdfDoc.numPages) {
        return;
      }
      prevPageNum = pageNum;
      pageNum++;
      queueRenderPage(pageNum);
    }
    document.getElementById('next').addEventListener('click', onNextPage);
    
    /**
     * Asynchronously downloads PDF.
     */
    pdfjsLib.getDocument(url).then(function(pdfDoc_) {
      pdfDoc = pdfDoc_;
      document.getElementById('page_count').textContent = pdfDoc.numPages;
    
      // Initial/first page rendering
      renderPage(pageNum);
    });
    
    // Adding a rectangle
    jQuery(function($) {
      $("#addRectangle").click(function() {
        fCanvas.add(new fabric.Rect({
          left: 100,
          top: 100,
          fill: 'red',
          width: 20,
          height: 20
        }));
      });
    });
    #the-canvas {
      border:1px solid black;
    }
    <script src="//mozilla.github.io/pdf.js/build/pdf.js"></script>
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script>
    <script src="https://rawgit.com/kangax/fabric.js/master/dist/fabric.js"></script>
    
    <h1>PDF.js Previous/Next example</h1>
    
    <div>
      <input type="button" id="addRectangle" value="Add Signature">
    
      <button id="prev">Previous</button>
      <button id="next">Next</button>
      &nbsp; &nbsp;
      <span>Page: <span id="page_num"></span> / <span id="page_count"></span></span>
    </div>
    
    <canvas id="the-canvas"></canvas>

    【讨论】:

    • 感谢您的解决方案,但似乎当我做下一个或上一个时,它在第一页本身就被击中了。每个页面可以有多个矩形。 ....
    • @ShankarGuru 只显示第一页,因为它每次都位于对象堆栈的顶部,请检查更新的答案。
    • 谢谢,它有帮助...有没有办法以字节数组或基数 64 获取更新的 pdf...我看到 fCanvas 仅指当前实例,而 pageHistory 只会访问过的实例...如果我更新了第一页和第二页,我是否可以将第一页和第二页更新为字节数组或 base 64 中的剩余页?
    • 试过了,但没有按预期工作...jsfiddle.net/p6oacqmu