Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
/picoPublic

Take browser screenshots in Javascript 📸

License

NotificationsYou must be signed in to change notification settings

rsify/pico

Repository files navigation


📸 Pico

Take browser screenshots in Javascript

npmGitHub issuesCompressed size

(Original page on the left · PNG output on the right)


Goal

Pico's goal is to produce high precision screenshots of any viewport entirelyclient side. This is different from simply capturing a webpage usingPuppeteer or a similar tool in thatthe screenshot taking happens entirely client side.

The viewport screenshots include scrolled element scroll states, cross-originimages, input states, web fonts, canvas contents, current video frame contents,and much more information that you wouldn't be able to get using something likea headless browser.

At the time of writing there are no existing solutions that are aimedof reproducing the entire viewport accurately like Pico.

How it works

Warning: nerdy

This program renders whatever is displayed in the givenWindow into animage, thanks to svg's<foreignObject>.

No server side code is required to produce the screenshot.

There is no native Javascript API to take the screenshot of what the user iscurrently seeing on their screen (and because of security issues thereprobably will never be one).

Since we don't have access to the raw data that's being shown to the user wehave to reconstruct it manually. This program works thanks to svg's<foreignObject> which lets you insert any valid HTML content inside, whichwe can then pass as a data URL into a<canvas>'drawImage and read outthe raw image data withcanvas.toBlob orcanvas.toDataURL.

The above alone would work great in a universe where subresources didn'texist - which as you know is not our universe. SVG's inserted into<img>tags (or in our case,<canvas>') cannot display any external resources,whether it's images, fonts or stylesheets.

To work around that fact Pico does the following things:

  • Downloads and inlines contents of all<img> tags as data URL's in theirsrcattributes
  • Downloads external stylesheets and inlines them as<style> tags
  • Checks all stylesheets for nested resources
    • Downloads and checks nested stylesheets in@import rules
    • Downloads any resources referenced by theurl() function, includingbut not exclusive to the following properties:
      • backgrounds
      • background-images
      • src in@font-face rule
      • cursor
      • content

In addition, Pico also:

  • Copies input states (text inputs, checkboxes, textareas) intovalueattributes so that they can be shown in SVG
  • Emulates current scroll positions on all scrolled elements (including theroot<html> element) via eithertransform: translate (for root node)andabsolute positioning of children of scrolled nodes
  • Transforms existing<canvas> elements into<img> tags with the contents of the<canvas>' inlined as data URL's insrc
  • Performs various minor fixes forrem font size, working media queries,preserving size of everything, etc.

The returned DOM is inserted into an<iframe>, serialized into XML,converted into a data URL, put into anImage, which is then rendered ontoa<canvas> whose contents are read out withcanvas.toBlob and finallyreturned to the program's caller, together with all the errors whenresources failed to load.

Pico is able to safely accumulate all async resource errors thanks toFluture, which is a really greatalternative to the nativePromise and forces you to write type safeerrors. You can read afantastic introductory article to it by thelibrary's author here.

API

Pico is built usingFluture and inaddition to thePromise also provides a direct API toFluture via functionssuffixed withFluture. If you don't care about functional programming justuse the non-suffixed functions to work withPromise's instead.

All functions return an "ErrorStack", which is basically just the returnedvalue paired with any errors that happened while computing it. Most errors willbe CORS or 404 related issues when loading subresources.

Types

declaretypeErrorStack<T>={errors:DetailedError[];value:T;};
exportdeclaretypeDetailedError={// Human readable string of why the error happenedreason:string;// Proper error objecterror:Error;};
exportdeclaretypeOptions={// An array of selectors to nodes that should not be included in the output.ignore:string[];};

Functions

declareconstobjectURL:($window:Window,partialOptions?:Partial<Options>)=>Promise<ErrorStack<string>>;declareconstobjectURLFluture:($window:Window,options:Options)=>Fluture<DetailedError,ErrorStack<string>>;

Render the givenWindow to a PNG image and return it as anobject URL.This is safer to use thandataURL due to memory constraints. Remember to callURL.revokeObjectURLwhen you're done with the image.


declareconstdataURL:($window:Window,partialOptions?:Partial<Options>)=>Promise<ErrorStack<string>>;declareconstdataURLFluture:($window:Window,options:Options)=>Fluture<DetailedError,ErrorStack<string>>;

Render the givenWindow to a PNG image and return it as adata url.Note thatin Chrome the limit for data url's is 2MB,preferobjectURL when possible.


declareconstsvgObjectURL:($window:Window,partialOptions?:Partial<Options>)=>Promise<ErrorStack<string>>;declareconstsvgObjectURLFluture:($window:Window,options:Options)=>Fluture<DetailedError,ErrorStack<string>>;

Render the givenWindow to an SVG image and return it as anobject URL.This function is mainly useful for inspecting the output of Pico usingdevtools, for real uses prefer the other functions.

Installation

$ npm install @gripeless/pico

The module is intended to be used exclusively in the browser via a code bundlerlike Rollup or Webpack. There is no single file bundle build provided at thistime.

Contributing

Seecontributing.md.

Caveats

Pico is being developed against recent Firefox and Blink based browsers(Chrome, Opera, Brave, Edge). It does not work on Safari or old Edge versionsdue to lack of proper support for<foreignObject>.

Prior art

Pico's code was inspired in many ways by the following libraries:

Pico's selling point is representing the whole viewportas accurately as possible. If you want to render a single DOM node instead,consider using one of the above libraries.

To the authors of the above code, thank you for your awesome work.

License

MIT

Releases

No releases published

Packages

No packages published

[8]ページ先頭

©2009-2025 Movatter.jp