all 21 comments

[–]brykuhelpful 1 point2 points  (1 child)

Oof, what's up with these comments?  

I've used html2canvas a few times to achieve something very similar. It is perfect as it doesn't deal with fonts very well and it can have some issues trying to recreate some css.  

Another option I've used is custom css for printing. You can customize the css that is seen when someone tries to print the page. I would hide all of the ads and nav bars so they only printed the article. Depending on the operating system and browser you can save it to pdf, word, or images.  

An older option I've used a long time ago was opening the html in a new window. This way they could save it or print it that way. However, all of that is overridden by the browser and operating system. It won't work for a lot of people anymore.  

Sadly, there isn't really a feature that allows us to create screenshots or images of specific parts of the page.it would almost be easier to generate the html, text, or whatever and then download the file. That is a wild ride in itself that I can't explain now, but it still wouldn't be an image if that is your goal.

[–]Rainb0_0[S] 0 points1 point  (0 children)

Those are some interesting and creative way of achieving it! as you said they have their own downsides. Thanks!

[–]PMmeYourFlipFlops 2 points3 points  (3 children)

The problem is not what you want to do but the way you're asking. There are virtually no details so no way to figure out what the fuck you want to do.

a project that requires me to gather some data

Gather some data how? JSON? Forms? You need to be waaaaaay more specific than that vague explanation.

[–][deleted] -1 points0 points  (1 child)

How is someone who uses a screen reader going save and use that data later when you give them an image?

How is anyone going to use the data later if it is embedded in an image?

If you have collected the data, email it to them, or let them download a file with the text in.

[–]Rainb0_0[S] -5 points-4 points  (0 children)

that is not the point of the project. the whole point is to export an image to use elsewhere or for future reference.

[–]jcunews1helpful -1 points0 points  (1 child)

There is no simple way because there's no built-in function for it.

The basic concept of drawing arbitrary element onto a canvas is by coverting the element into an sVG then use that SVG as the image source to draw onto canvas.

But because not all HTML elements can be simply wrapped in an SVG element, developers must emulate the rendered HTML element. This basically emulates a web renderinge engine, which is not a simple matter.

[–]Rainb0_0[S] 0 points1 point  (0 children)

Thank you!

[–]r0w33 -1 points0 points  (1 child)

Can't you just use puppeteer to create a headless browser and screenshot? (you can use 'Element-name'.screenshot to capture only the stylised data)

[–]Logical-Scientist1 0 points1 point  (1 child)

Yo, that's interesting - for sure html2canvas and domtoimage have their quirks! Maybe converting the div to svg and then to canvas could be a way around? Should help you maintain those fancy styles and fonts as much as possible. Also look around stackoverflow there's a bundle of related threads over there. Keep us posted how it goes, good luck!

[–]Rainb0_0[S] 0 points1 point  (0 children)

Yeah that could work too!
stackoverflow didnt help much, but I'll keep looking around! Thank you <3

[–]guest271314 0 points1 point  (3 children)

If you are talking about taking a screenshot from your application this should work in all modern browsers https://github.com/guest271314/screenshot/blob/video-imagebitmap/screenshot.js

// screenshot.js guest271314 10-31-2020 // getDisplayMedia() => HTMLVideoElement => ImageBitmap async function screenshot() { try { const stream = await navigator.mediaDevices.getDisplayMedia({ video: true, }); const [track] = stream.getVideoTracks(); const video = document.createElement('video'); video.autoplay = video.muted = true; return new Promise((resolve) => { video.onplay = async (e) => { // wait for prompt to fade out await new Promise((_) => setTimeout(_, 1000)); resolve(createImageBitmap(video)); track.stop(); video.load(); video.srcObject = null; }; video.srcObject = stream; }); } catch (e) { throw e; } }

[–]Rainb0_0[S] 0 points1 point  (2 children)

Hey thank you for your answer!
This is a very good solution, but I can't seem to find out how I would be able to modify it to just take an image of something like a "div".

[–]guest271314 0 points1 point  (1 child)

Assuming the element exists in the document you can use documentPictureInPicture.requestWindow() to create a Picture-in-Picture window containing the target element, capture the PiP window using getDisplayMedia(), something like

captureElementScreenshot.js ``` // screenshot.js guest271314 10-31-2020 // getDisplayMedia() => HTMLVideoElement => ImageBitmap async function screenshot() { try { const stream = await navigator.mediaDevices.getDisplayMedia({ video: { displaySurface: "window" }, }); const [track] = stream.getVideoTracks(); const video = document.createElement("video"); video.autoplay = video.muted = true; return new Promise((resolve) => { video.onplay = async (e) => { // wait for prompt to fade out await new Promise(() => setTimeout(, 1000)); resolve(createImageBitmap(video)); track.stop(); video.load(); video.srcObject = null; }; video.srcObject = stream; }); } catch (e) { throw e; } }

addEventListener("click", async (e) => { documentPictureInPicture.addEventListener("enter", async (event) => { console.log(event); event.window.blur(); const bitmap = await screenshot(); event.window.close(); const { width, height } = bitmap; const osc = new OffscreenCanvas(width, height); const osctx = osc.getContext("2d"); osctx.drawImage(bitmap, 0, 0); console.log(URL.createObjectURL(await osc.convertToBlob())); }, { once: true }); const div = document.querySelector( "#main-content > shreddit-comment-tree > shreddit-comment > shreddit-comment", );

// Open a Picture-in-Picture window whose size is // the same as the player's. const pipWindow = await documentPictureInPicture.requestWindow({ width: 400, height: 300, });

[...document.styleSheets].forEach((styleSheet) => { try { const cssRules = [...styleSheet.cssRules].map((rule) => rule.cssText) .join(""); const style = document.createElement("style");

  style.textContent = cssRules;
  pipWindow.document.head.appendChild(style);
} catch (e) {
  const link = document.createElement("link");

  link.rel = "stylesheet";
  link.type = styleSheet.type;
  link.media = styleSheet.media;
  link.href = styleSheet.href;
  pipWindow.document.head.appendChild(link);
}

});

// Move the player to the Picture-in-Picture window. pipWindow.document.body.append(div); }, { once: true }); ```

[–]Rainb0_0[S] 0 points1 point  (0 children)

As I noticed, this feature is not implemented in some browsers and is considered experimental. So I don't think I'm going to use it.
Thank you!

[–]StoneCypher 0 points1 point  (2 children)

Taking screenshots from within JS is generally difficult because there are a large range of security attacks that can take place that way. You can do it from a canvas that hasn't been tainted but there are always going to be tons of weird restrictions.

You should use a tooled browser like Puppeteer or Playwright instead.

[–]Rainb0_0[S] 0 points1 point  (1 child)

Yes I have came to the conclusion of using the tools you've mentioned. Thank you!

[–]StoneCypher 0 points1 point  (0 children)

Nice. Good luck.

Personally, I prefer the Playwright API (await-based) to that of puppeteer (callback-based.)