└── screenshooter ├── description.yaml ├── README.md ├── __init__.py └── main.js /screenshooter/description.yaml: -------------------------------------------------------------------------------- 1 | Type: Jupyter Notebook Extension 2 | Compatibility: 3.x, 4.x, 5.x, 6.x 3 | Name: Screen shooter 4 | Main: main.js 5 | Link: README.md 6 | Description: | 7 | Adds the ability to easily take screenshots and save them into the notebook. 8 | 9 | Parameters: 10 | - none 11 | -------------------------------------------------------------------------------- /screenshooter/README.md: -------------------------------------------------------------------------------- 1 | Screen shooter 2 | 3 | ========= 4 | 5 | Adds the ability to easily take screenshots and save them into the notebook. 6 | to use: 7 | * click the button 8 | * select the capture source (e.g. full screen, a specific application, etc...) 9 | * A cell will be added (above the currently selected cell) with the screenshot 10 | 11 | This extenstion is a work in progress to assist with workflow documentation. 12 | -------------------------------------------------------------------------------- /screenshooter/__init__.py: -------------------------------------------------------------------------------- 1 | import os 2 | from glob import glob 3 | 4 | from setuptools import find_packages, setup 5 | 6 | setup( 7 | name='screen_shooter_nbextension', 8 | version='0.1dev', 9 | license='Creative Commons Attribution-Noncommercial-Share Alike license', 10 | long_description="Adds the ability to easily take screenshots and save them into the notebook.", 11 | author='mstern', 12 | 13 | packages=['screenshooter',], 14 | install_requires=[ 15 | 'jupyter_core', 16 | 'notebook >=4.0', 17 | ], 18 | # jupyter server 19 | zip_safe=False, 20 | include_package_data=True, 21 | data_files=[ 22 | # like `jupyter nbextension install --sys-prefix` 23 | ("share/jupyter/nbextensions/screenshooter", [ 24 | "screenshooter/static/index.js", 25 | ]), 26 | # like `jupyter nbextension enable --sys-prefix` 27 | ("etc/jupyter/nbconfig/notebook.d", [ 28 | "jupyter-config/nbconfig/notebook.d/screenshooter.json" 29 | ]), 30 | # like `jupyter serverextension enable --sys-prefix` 31 | ("etc/jupyter/jupyter_notebook_config.d", [ 32 | "jupyter-config/jupyter_notebook_config.d/screenshooter.json" 33 | ]) 34 | ] 35 | ) 36 | 37 | 38 | if __name__ == '__main__': 39 | main() 40 | -------------------------------------------------------------------------------- /screenshooter/main.js: -------------------------------------------------------------------------------- 1 | define([ 2 | 'base/js/namespace', 3 | 'base/js/events' 4 | ], function(Jupyter, events) { 5 | 6 | // Adds a cell above current cell (will be top if no cells) 7 | var add_cell = function() { 8 | const uuid = UID(); 9 | 10 | $(`
11 | 12 | 13 |
`).appendTo(document.body); 14 | 15 | Jupyter.notebook.insert_cell_above('markdown').set_text("\nscreenshot"); 16 | Jupyter.notebook.select_prev(); 17 | CaptureNow(uuid); 18 | }; 19 | // Button to add default cell 20 | var defaultCellButton = function () { 21 | Jupyter.toolbar.add_buttons_group([ 22 | Jupyter.keyboard_manager.actions.register ({ 23 | 'help': 'take screenshot', 24 | 'icon' : 'fa-image', 25 | 'handler': add_cell 26 | }, 'screenshooter', 'screen shot') 27 | ]) 28 | }; 29 | var prefix = 'screenShooter'; 30 | var action_name = 'take_screenShot'; 31 | 32 | // Run on start 33 | function load_ipython_extension() { 34 | defaultCellButton(); 35 | } 36 | 37 | var UID = function () { 38 | // generates a random ID so we can easily have multiple screenshots saved 39 | return '_' + Math.random().toString(36).substr(2, 9); 40 | }; 41 | /* Main Screen shooter */ 42 | function CaptureNow(uuid) { 43 | // connect to image & video 44 | console.log('screenshot '+uuid+' capturing'); 45 | var videoElem = document.getElementById("video"+uuid); 46 | var image = document.getElementById("image"+uuid); 47 | var ourDiv = document.getElementById("section"+uuid); 48 | // hey user select what they want to capture 49 | navigator.mediaDevices.getDisplayMedia({ 50 | audio: false, 51 | video: true 52 | }) 53 | .then(mediaStream => { 54 | videoElem.srcObject = mediaStream; 55 | // Stop the stream after .1 seconds 56 | setTimeout(() => { 57 | const tracks = mediaStream.getTracks() 58 | tracks[0].stop() 59 | }, 100) 60 | return videoElem.play(); 61 | }).then(() => { // enable the button 62 | takeASnap(videoElem, image); 63 | ourDiv.remove(); 64 | }) 65 | }; 66 | /* Helper methods to take screenshot */ 67 | function takeASnap(videoElem, image) { 68 | const canvas = document.createElement('canvas'); // create a canvas 69 | const ctx = canvas.getContext('2d'); // get its context 70 | canvas.width = videoElem.videoWidth; // set its size to the one of the video 71 | canvas.height = videoElem.videoHeight; 72 | ctx.drawImage(videoElem, 0, 0); // the video 73 | 74 | canvas.toBlob(download(image), 'image/jpeg'); 75 | // return new Promise((res, rej) => { 76 | // canvas.toBlob(res, 'image/jpeg'); // request a Blob from the canvas 77 | // }); 78 | } 79 | 80 | function download(image) { 81 | // ad to img tag 82 | return function(blob) { 83 | console.log( blob ); 84 | Jupyter.notebook.get_selected_cell(). 85 | insert_inline_image_from_blob(blob); 86 | 87 | setTimeout(function(){ 88 | Jupyter.notebook.execute_cell_and_select_below(); 89 | }, 500); 90 | 91 | var reader = new FileReader(); 92 | reader.readAsDataURL(blob); 93 | reader.onloadend = function() { 94 | image.src = reader.result; 95 | } 96 | } 97 | } 98 | 99 | return { 100 | load_ipython_extension: load_ipython_extension 101 | }; 102 | }); 103 | --------------------------------------------------------------------------------