Is it possible to to take a screenshot of an iframe in a web page?
Asked Answered
R

6

10

I'm trying to take a screenshot of an iframe in a webpage. In my particular case, the iframe contains the Street View of one of my clients' store. As far as I've searched and read, I didn't find any solution to this.

I know there are JavaScript libraries like Html2Canvas and Canvas2Image, but they are not able to capture an iframe.

Here is the fiddle I'm working on that.

These libraries are working properly with every HTML element, except the iframe.

This is the JavaScript of the fiddle:

$(function() { 
        $("#btnSave").click(function() { 
        html2canvas($("#widget"), {
            onrendered: function(canvas) {
                var context=canvas.getContext("2d"); // returns the 2d context object
                // Convert and download as image 
                theCanvas = canvas;
                document.body.appendChild(canvas);

                // Convert and download as image 
                Canvas2Image.saveAsPNG(canvas); 
                $("#img-out").append(canvas);
            }
        });
    });
});

Does any other way to capture an iframe exist? Are there any paid third-party services that can do this?

If nothing will work with an iframe, are there any alternatives to achieve what I'm trying to do?

Please tell me if more informations are needed.

Any help will be greatly appreciated.

Thanks in advance

Reeve answered 11/6, 2019 at 12:24 Comment(0)
S
3

If you need to do the capture in a programmed way, you have the option of using nodejs with puppeteer which is a library that uses chromium to simulate a web browser. I give you an example to capture the screen:

const puppeteer = require('puppeteer');

async function run() {
    let browser = await puppeteer.launch({ headless: false });
    let page = await browser.newPage();
    await page.goto('https://www.scrapehero.com/');
    await page.screenshot({ path: './image.jpg', type: 'jpeg' });
    await page.close();
    await browser.close();
}

run();

Here is the source where I got it from: https://www.scrapehero.com/how-to-take-screenshots-of-a-web-page-using-puppeteer/

Sukey answered 11/6, 2019 at 12:44 Comment(0)
F
2

There is a solution, when you use html2canvas, the input variable must be an HTMLElement, then it will create the screenshot. It is supported by old browsers too (like IE9), check the documentation: https://html2canvas.hertzen.com/documentation.html

import html2canvas from 'html2canvas';

screenShot() {
  const iframe = document.getElementsByTagName('iframe');
  const screen = iframe[0]?.contentDocument?.body;

  html2canvas(screen)
    .then((canvas) => {
      const base64image = canvas.toDataURL('image/png');

     // Do something with the image
  });
}
Filemon answered 22/2, 2021 at 11:47 Comment(1)
This takes the screenshot of other elements but hides the iframe from resultant image. Note: My iframe is on a different domain.Dactylo
H
1

If you just want to take a screenshot, just use a snipping tool for that (but I guess this is not your case).

From a programming perspective:

Consider that the iframe loads an external page within your website and you do not have control on this. The loaded page code is NOT part of your source code, and little to no control you have over it for extensive editing/capabilities, programmatically.

As stated here, you can use the getScreenshot method of the iframe in FF. This might work for you, but I guess this could be useful for a simple scenario and could not be considered as a full, cross-browser compartibility solution used as a feature.

Heartfelt answered 11/6, 2019 at 12:30 Comment(0)
N
1

You can't, because they are seperate documents. The only way to achieve that would be to manipulate the page's code before printing so that the iframe was bigger, but this would have to be done by hand since the iframe's width and height may not be the only page elements actually limiting it's sizing. For example the iframe could be inside several other div tags that have fixed sizes. You'd also need to know the height and width of the content being shown in the iframe so you'd know how big to make the iframe's new size.

Northeastward answered 11/6, 2019 at 13:1 Comment(0)
E
1

In a browser and using the same method ugyanakkor explained, dom-to-image-more now supports same origin and blob iframe support (implemented by me). It may not have been put to an npm registry though; if that, then add dom-to-image-more.js to your codes.

Editor answered 15/9, 2021 at 15:42 Comment(0)
P
0

In case the iframe comes from an external source, content will not be accessible to you, so the solutions as html2canvas will not work.

I ended using the Screen Capture API, which is the only solution. The disadvantage is the user has to give access to the API, and choose the right tab he wants to capture.

The trick here is to capture only a specific element in the screen. I place the screenshot button with an absolute position, inside the same div than the iframe, so it will have the same starting x and y coordinates. You can move the button somewhere else and add the displacement to drawImage.

Here is a snippet :

let button = document.querySelector("#screenshotButton");
let iframe = document.querySelector("#screenshotIframe");

button.addEventListener("mouseup", async(event) => {
  const buttonRect = button.getBoundingClientRect();
  const iFrameRect = iframe.getBoundingClientRect();

  // compute where do we click inside the button
  const diffX = event.clientX - buttonRect.x;
  const diffY = event.clientY - buttonRect.y;

  // Determine the fixed screen iframe coordinates
  const iFrameScreenX = event.screenX - diffX;
  const iFrameScreenY = event.screenY - diffY;

  // Create our temporary media elements
  const video = document.createElement("video");
  video.width = iFrameRect.width;
  video.height = iFrameRect.height;

  const canvas = document.createElement("canvas");
  canvas.width = iFrameRect.width;
  canvas.height = iFrameRect.height;

  const context = canvas.getContext("2d");
  if (!context) return;

  // Ratio between device pixels and css pixels
  const ratio = window.devicePixelRatio;

  try {
    const captureStream = await navigator.mediaDevices.getDisplayMedia();
    video.srcObject = captureStream;
    video.onloadeddata = () => {
      context.drawImage(
        video,
        iFrameScreenX * ratio - window.screenX * ratio,
        iFrameScreenY * ratio - window.screenY * ratio,
        iFrameRect.width * ratio,
        iFrameRect.height * ratio,
        0,
        0,
        iFrameRect.width,
        iFrameRect.height,
      );
      captureStream.getTracks().forEach((track) => track.stop());

      canvas.toBlob((blob) => {
        // save your blob here
        // const formData = new FormData();
        // formData.append("file", blob ?? "");
        console.log(blob);
      }, "image/jpeg");
    };
  } catch (err) {
    console.error("Error during screenshot : " + err);
  }
});
<div>
  <button style="position: absolute;" id="screenshotButton">
    Shot
  </button>
  <iframe title="screenshotIframe" id="screenshotIframe" src="https://www.orpha.net" width="100%" height="100%"></iframe>
</div>
Payload answered 23/5 at 10:47 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.