Giter Club home page Giter Club logo

selfie's Introduction

Selfie

Selfie is a JavaScript library for taking screenshots of own page. It uses the getDisplayMedia API to get either a tab screenshot or a full screen screenshot and optionally crops out a marked area (using two pixel markers) of the page.

This is an alternative method to html2canvas.

There is a early draft of a proposal to introduce a native browser API for capturing self-screenshots. It is in its early stages and there is no implementation yet that I'm aware of.

Demo

https://tomashubelbauer.github.io/selfie

Installation

Helper Script

This script displays a button for the user to click and initiate the screen share and then either returns the shared surface (tab or screen) or, if selector argument is provided, crops the image to just the element's area.

const { default: selfie } = await import('https://tomashubelbauer.github.io/selfie/selfie.js');
selfie(); // or selfie('selector') to capture a given element

The helper script exists to show a sample of implementation, you're most likely going to want to build the flow around this yourself, inspired by it.

script Tag

<script src="https://tomashubelbauer.github.io/selfie/snap.js"></script>

ESM import

import snap from 'https://tomashubelbauer.github.io/selfie/snap.js';

ESM await import

const { default: snap } = await import('https://tomashubelbauer.github.io/selfie/snap.js');

Usage

Bare Shared Surface

Make a call to snap from within a stack trace user interaction initiated. Most likely this is going to be a button press. This is a requirement for the getDisplayMedia API to function correctly. You'll get back a canvas element containing the shared surface (tab or screen). You can call toDataURL on it, call getContext to further work with the image (e.g. using getImageData) or do anything else you like with it.

button.addEventListener('click', async () => document.body.append(await snap()));

Marked Area

Show two pixel markers: red and lime. Surround both pixel markers with a white border to remove any effect of the share stream compression on the pixel colors. Mark the top-left corner of the area with red and bottom-right with lime.

Direct the user to select the current tab or just share the whole screen.

Make a call to snap from within a stack trace user interaction initiated. Most likely this is going to be a button press. This is a requirement for the getDisplayMedia API to function correctly.

Hide the pixel markers - they are not needed anymore. Call scan with the canvas from snap and provide it with the dimensions of the marked area as well. You'll get an object with the marked region information, e.g.: { x, y, width, height }.

button.addEventListener('click', async () => {
  document.body.append(scan(await snap(), width, height));
});

Work with the canvas and the region data in any way you like, or use the crop function provided by Selfie to crop the original canvas into a new canvas with just the marked region.

button.addEventListener('click', async () => {
  document.body.append(crop(scan(await snap(), width, height)));
});

Development

Run using npx serve . (http://localhost:5000) instead of off file protocol. This is needed for ESM and canvas CORS to work correctly.

How it works

Capturing a screenshot of whatever the user selects in the browser UI when asked is done by using the getDisplayMedia API which returns a stream which we stop right after we capture its first frame.

Capturing a particular area is done by displaying two marker pixels described in the Usage section above while taking the screenshot. Afterwards, an algorithm is used to find the location of the red marker in the screenshot and the knowledge of the offset between the two markers provides us with all the information we need to check the lime marker is there as expected and crop the original image down to just the marked area.

The algorithm works by assuming:

  • There are two marker pixels: red (top-left) and lime (bottom-right)
  • The two markers are offset by a known size provided by the caller
  • The marked are is rectangular and not rotated or scaled, only translated

Support

I've tested the library works in Mozilla Firefox and Google Chrome. I've also tested Safari. In macOS Safari, the user is not asked for a window to select, the entire screen is shared immediately. In iOS Safari, getDisplayMedia is not supported.

Notes

To-Do

Take a look at the ImageCapture API to use instead of canvas

It is currently not supported in Firefox but once it gains support it will make for a much nicer API to use.

https://developer.mozilla.org/en-US/docs/Web/API/ImageCapture

Configure the media stream constraints better once they are well supported

Firefox lacks support for many of these as of now.

https://developer.mozilla.org/en-US/docs/Web/API/MediaTrackSettings/cursor

Disable cursor because we are not waiting for the user to point anywhere.

https://developer.mozilla.org/en-US/docs/Web/API/MediaTrackConstraints/displaySurface

Consider preselecting browser so we automatically get out current tab and do not have to ask the user to select it. We'd still do the auto-crop but just to get rid of the browser UI and handle Safari which still returns full screen.

https://developer.mozilla.org/en-US/docs/Web/API/MediaTrackConstraints/logicalSurface

Not sure what this is completely, so check by checking what I get for the various options provided by the browser:

https://developer.mozilla.org/en-US/docs/Web/API/MediaTrackConstraints/logicalSurface#usage_notes

Fix the artifact tool color indicator label displaying bad color when panned

selfie's People

Contributors

tomashubelbauer avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar

Forkers

chris-han

selfie's Issues

Pass the coordinates directly?

I'd like to use it to screenshot a specific DOM element for Selenium-like automation.
How do I specify the coordinates directly instead of the pixel markers? I could just use the boundingRect property to figure out the coordinates myself and then pass it to this utility. Also I'll need some chrome extension to suppress the security policy by default.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.