niklasvh / html2canvas

Screenshots with JavaScript
https://html2canvas.hertzen.com/
MIT License
30.52k stars 4.8k forks source link

screenshot of webcam issue #2737

Closed marcusx2 closed 2 years ago

marcusx2 commented 2 years ago

Following this tutorial I could take a screenshot of the webcam, but the problem is that half of the picture is white. Why is that?

IMG-20211026-WA0013

marcusx2 commented 2 years ago

Hi @niklasvh, I'm using html2canvas to take a screenshot of an ar application. I'm using arjs, their image tracking example. With some slight modification, I added the code to use html2canvas and take a screenshot of the video tag. But there are 2 problems: 1- Half of the screen is white. It's like the screenshot doubles the size of the screen, with the half on the left being the picture and the right being white, like on my first comment. 2- The second problem is that the screenshot doesn't add the augmented reality content. Point your phone to this tracking https://raw.githubusercontent.com/AR-js-org/AR.js/master/aframe/examples/image-tracking/nft/trex-image-big.jpeg . You will see the dinosaur, but if you take a screenshot the dinosaur won't be seen. How can I fix this?

My sample html takes a screenshot and invokes the sharing functionality to preview the image. It takes the screenshot on the document pointerdown, and share on pointerup. So just hold your finger on the screen for 5 seconds and release, it should work.

You need to run using https, like a live-server-https.

Here is the html sample code

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="utf-8">
    <script src="https://cdn.jsdelivr.net/gh/aframevr/aframe@1c2407b26c61958baa93967b5412487cd94b290b/dist/aframe-master.min.js"></script>
    <script src="https://raw.githack.com/AR-js-org/AR.js/master/aframe/build/aframe-ar-nft.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/html2canvas/1.3.2/html2canvas.min.js"></script>
    <style>
      .arjs-loader {
        height: 100%;
        width: 100%;
        position: absolute;
        top: 0;
        left: 0;
        background-color: rgba(0, 0, 0, 0.8);
        z-index: 9999;
        display: flex;
        justify-content: center;
        align-items: center;
      }

      .arjs-loader div {
        text-align: center;
        font-size: 1.25em;
        color: white;
      }
    </style>
    <script>
        let shareData;
        document.addEventListener('pointerdown', (event) => {
            function captureVideos() {
              var canvas = document.getElementById("canvas"); // declare a canvas element in your html
              var ctx = canvas.getContext("2d");
              var videos = document.querySelectorAll("video");
              var i, w, h;

              for (i = 0, len = videos.length; i < len; i++) {
                const v = videos[i];

                try {
                    w = v.videoWidth;
                    h = v.videoHeight;
                    canvas.width = w;
                    canvas.height = h;
                    ctx.fillRect(0, 0, w, h);
                    ctx.drawImage(v, 0, 0, w, h);
                    const a = canvas.toDataURL();
                    v.style.backgroundImage = "url(" + a + ")";
                    //v.style.backgroundSize = "contain";
                    ctx.clearRect(0, 0, w, h); // clean the canvas
                    canvas.width = canvas.height = 0;
                } catch(e) {
                    console.log(e);
                }
              }
            }

            captureVideos();
            html2canvas(document.body, {scrollX:-window.scrollX, scrollY: -window.scrollY, allowTaint: true}).then(function(canvas) {
                function dataURLtoFile(dataurl) {
                    var bstr = atob(dataurl.split(',')[1]), n = bstr.length, u8arr = new Uint8Array(n);
                    while(n--){
                        u8arr[n] = bstr.charCodeAt(n);
                    }
                    return u8arr;
                }

                const dataURL = canvas.toDataURL();
                const byteArray = dataURLtoFile(dataURL);
                shareData = {
                    files: [new File([byteArray], "bla.png", {type: "image/png"})]
                };
                console.log("finished");
            });
        });

        document.addEventListener("pointerup", () => {
            console.log("yeah");
            console.log(shareData);
            navigator.share(shareData).then(function()    {}).catch(function(err) {console.error(err);});
        }, {once: true})
    </script>
</head>

<body style="margin : 0px; overflow: hidden;">
  <!-- minimal loader shown until image descriptors are loaded -->
  <div class="arjs-loader">
    <div>Loading, please wait...</div>
  </div>
  <a-scene
    vr-mode-ui="enabled: false;"
    renderer="logarithmicDepthBuffer: true;"
    embedded
    arjs="trackingMethod: best; sourceType: webcam;debugUIEnabled: false;"
  >
    <!-- we use cors proxy to avoid cross-origin problems -->
    <a-nft
      type="nft"
      url="https://arjs-cors-proxy.herokuapp.com/https://raw.githack.com/AR-js-org/AR.js/master/aframe/examples/image-tracking/nft/trex/trex-image/trex"
      smooth="true"
      smoothCount="10"
      smoothTolerance=".01"
      smoothThreshold="5"
    >
      <a-entity
        gltf-model="https://arjs-cors-proxy.herokuapp.com/https://raw.githack.com/AR-js-org/AR.js/master/aframe/examples/image-tracking/nft/trex/scene.gltf"
        scale="5 5 5"
        position="50 150 0"
      >
      </a-entity>
    </a-nft>
    <a-entity camera></a-entity>
  </a-scene>
  <canvas id="canvas" hidden></canvas>
</body>
</html>

Thank you for your time. Please help...

marcusx2 commented 2 years ago

I solved the first issue by using the option {width: window.screen.availWidth}. Issue 2 remains.

marcusx2 commented 2 years ago

Fixed the issue, see here